app/jobs/lcms/engine/document_generate_job.rb
# frozen_string_literal: true
module Lcms
module Engine
class DocumentGenerateJob < Lcms::Engine::ApplicationJob
include ResqueJob
include RetryDelayed
queue_as :default
WAIT_FOR_JOBS = %w(
Lcms::Engine::MaterialGenerateJob
Lcms::Engine::MaterialGeneratePdfJob
Lcms::Engine::MaterialGenerateGdocJob
).freeze
def perform(document, check_queue: false)
@document = document
# Job has been queued from Material job
if check_queue
# Exit if any material is still generating
return if materials_generating?
elsif document.materials.any?
# Queue all materials at the first time
create_gdoc_folders
return queue_materials
end
# If came here:
# - all materials have been generated
# - document doesn't have any materials at all
#
# So need to check if such job is already running or has been already queued.
# And return in such case
return if queued?
if document.math?
document.document_parts.default.each { |p| p.update!(content: EmbedEquations.call(p.content)) }
end
queue_documents
end
private
attr_accessor :document
def create_gdoc_folders
return unless DocTemplate.document_contexts.include?('gdoc') || DocTemplate.material_contexts.include?('gdoc')
DocumentExporter::Gdoc::Base.new(document).create_gdoc_folders("#{document.id}_v#{document.version}")
end
#
# Checks if there are jobs queued or running for current document
# and any of its materials
#
def materials_generating? # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
document.materials.each do |material|
queued = Resque.peek(queue_name, 0, 0)
.map { |job| job['args'].first }
.detect { |job| same_material?(job, material.id) }
queued ||=
Resque::Worker.working.map(&:job).detect do |job|
next unless job.is_a?(Hash) && (args = job.dig 'payload', 'args').is_a?(Array)
args.detect { |x| same_material?(x, material.id) }
end
return true if queued
end
false
end
def same_document?(job, type, klass)
job['job_class'] == klass &&
job['arguments'].first['_aj_globalid'].index("gid://content/Document/#{document.id}") &&
job['arguments'].second['content_type'] == type
end
def same_material?(job, id)
WAIT_FOR_JOBS.include?(job['job_class']) &&
job['arguments'].first['_aj_globalid'].index("gid://content/Material/#{id}") &&
job['arguments'].second['_aj_globalid'].index("gid://content/Document/#{document.id}")
end
def same_self?(job)
job['job_class'] == self.class.name && job['job_id'] != job_id &&
job['arguments'].first.try(:[], '_aj_globalid') == "gid://content/Document/#{document.id}"
end
def queue_documents
DocumentGenerator::CONTENT_TYPES.each do |type|
DocumentGenerator.document_generators.each do |klass|
next if queued_or_running?(type, klass)
klass.constantize.perform_later document, content_type: type
end
end
end
def queue_materials
document.materials.each { |material| Lcms::Engine::MaterialGenerateJob.perform_later(material, document) }
end
def queued?
queued = Resque.peek(queue_name, 0, 0).map { |job| job['args'].first }.detect { |job| same_self?(job) }
queued || Resque::Worker.working.map(&:job).detect do |job|
next unless job.is_a?(Hash) && (args = job.dig 'payload', 'args').is_a?(Array)
args.detect { |x| same_self?(x) }
end
end
def queued_or_running?(type, klass)
queued = Resque.peek(queue_name, 0, 0)
.map { |job| job['args'].first }
.detect { |job| same_document?(job, type, klass) }
queued ||
Resque::Worker.working.map(&:job).detect do |job|
next unless job.is_a?(Hash) && (args = job.dig 'payload', 'args').is_a?(Array)
args.detect { |x| same_document?(x, type, klass) }
end
end
end
end
end