log job ids in exports and imports

if something goes wrong, but not so wrong that the entire export
or import fails (so there is no captured exception), it's
essentially impossible to review logs of the migration. if we
store the job id, we can provide it to the log-downloader script.

test plan:
 1. a. perform a common cartridge export
    b. in the console, examine ContentExport.last and ensure
       settings[:job_id] is set
    c. look at log/delayed_job.log and verify the log lines
       for the recent export include that id
 2. a. perform a course copy
    b. in the console, examine ContentMigration.last and ensure
       migration_settings[:job_ids] contains a job id
 3. a. perform a common cartridge import, choosing to import everything
    b. same as 2(b)
 4. a. perform a common cartridge import, choosing to import selectively
    b. make some kind of selection and complete the import
    c. ensure migration_settings[:job_ids] contains two job ids
       (one for each stage of the migration)

flag = none
closes LS-2730

Change-Id: I5d4028f4384111a06fa10d6327dce99c487fb9d6
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275929
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Nate Armstrong <narmstrong@instructure.com>
QA-Review: Nate Armstrong <narmstrong@instructure.com>
Product-Review: Jeremy Stanley <jeremy@instructure.com>
This commit is contained in:
Jeremy Stanley 2021-10-13 17:07:02 -06:00
parent 44f0499381
commit cabece352d
9 changed files with 81 additions and 0 deletions

View File

@ -134,6 +134,8 @@ class ContentExport < ActiveRecord::Base
end
def export(opts = {})
save if capture_job_id
self.shard.activate do
opts = opts.with_indifferent_access
case export_type
@ -152,6 +154,14 @@ class ContentExport < ActiveRecord::Base
end
handle_asynchronously :export, :priority => Delayed::LOW_PRIORITY, :max_attempts => 1, :on_permanent_failure => :fail_with_error!
def capture_job_id
job = Delayed::Worker.current_job
return false unless job
self.settings[:job_id] = job.id
true
end
def reset_and_start_job_progress
self.job_progress.try :reset!
self.job_progress.try :start!

View File

@ -538,9 +538,21 @@ class ContentMigration < ActiveRecord::Base
Canvas::Plugin::value_to_boolean option
end
def capture_job_id
job = Delayed::Worker.current_job
return false unless job
self.migration_settings[:job_ids] ||= []
return false if self.migration_settings[:job_ids].include?(job.id)
self.migration_settings[:job_ids] << job.id
true
end
def import_content
reset_job_progress(:running) if !import_immediately?
self.workflow_state = :importing
capture_job_id
self.save
Lti::Asset.opaque_identifier_for(self.context)

View File

@ -20,6 +20,7 @@
class Canvas::Migration::Worker::CourseCopyWorker < Canvas::Migration::Worker::Base
def perform(cm = nil)
cm ||= ContentMigration.find migration_id
cm.save if cm.capture_job_id
cm.workflow_state = :pre_processing
cm.reset_job_progress

View File

@ -20,6 +20,7 @@
class Canvas::Migration::Worker::ZipFileWorker < Canvas::Migration::Worker::Base
def perform(cm = nil)
cm ||= ContentMigration.find migration_id
cm.save if cm.capture_job_id
cm.workflow_state = :importing
cm.migration_settings[:skip_import_notification] = true

View File

@ -20,6 +20,7 @@
class CC::Importer::CCWorker < Canvas::Migration::Worker::Base
def perform(cm = nil)
cm ||= ContentMigration.where(id: migration_id).first
cm.save if cm.capture_job_id
cm.job_progress.start unless cm.skip_job_progress
begin
cm.update_conversion_progress(1)

View File

@ -358,6 +358,43 @@ describe ContentMigrationsController, type: :request do
expect(migration.copy_options).to eq({ 'assignments' => { key => '1' } })
end
it "records both jobs involved with a selective import" do
# create the migration, specifying selective import
json = api_call(:post,
@migration_url,
@params,
{
:migration_type => 'canvas_cartridge_importer',
:selective_import => '1',
:pre_attachment => { :name => 'example.imscc' }
})
expect(json['workflow_state']).to eq 'pre_processing'
# (pretend to) upload the file
cm = ContentMigration.find json['id']
file = Attachment.new(context: cm, display_name: 'example.imscc')
file.uploaded_data = fixture_file_upload('migration/canvas_cc_minimum.zip')
file.save!
cm.attachment = file
cm.save!
cm.queue_migration
allow(Delayed::Worker).to receive(:current_job).and_return(double("Delayed::Job", id: 123))
run_jobs
expect(cm.reload.workflow_state).to eq 'exported'
expect(cm.migration_settings['job_ids']).to eq([123])
# update the migration with the selection
json = api_call(:put,
"#{@migration_url}/#{cm.id}",
@params.merge(:action => 'update', :id => cm.to_param),
{ :copy => { 'everything' => '1' } })
expect(json['workflow_state']).to eq 'running'
allow(Delayed::Worker).to receive(:current_job).and_return(double("Delayed::Job", id: 456))
run_jobs
expect(cm.reload.workflow_state).to eq 'imported'
expect(cm.migration_settings['job_ids']).to match_array([123, 456])
end
it "queues for course copy on concluded courses" do
source_course = Course.create(name: 'source course')
source_course.enroll_teacher(@user)

View File

@ -26,6 +26,12 @@ describe ContentExport do
@ce = @course.content_exports.create!
end
it "records the job id" do
allow(Delayed::Worker).to receive(:current_job).and_return(double("Delayed::Job", id: 123))
@ce.export(synchronous: true)
expect(@ce.reload.settings[:job_id]).to eq(123)
end
context "export_object?" do
it "returns true for everything if there are no copy options" do
expect(@ce.export_object?(@ce)).to eq true

View File

@ -62,6 +62,12 @@ describe ContentMigration do
expect(@cm.finished_at.to_i).to eq time.to_i
end
it "records the job id" do
allow(Delayed::Worker).to receive(:current_job).and_return(double("Delayed::Job", id: 123))
run_course_copy
expect(@cm.reload.migration_settings[:job_ids]).to eq([123])
end
it "migrates syllabus links on copy" do
course_model

View File

@ -217,6 +217,13 @@ describe ContentMigration do
test_zip_import(@course, cm)
end
it "records the job id" do
allow(Delayed::Worker).to receive(:current_job).and_return(double("Delayed::Job", id: 123))
cm = setup_zip_import(@course)
test_zip_import(@course, cm)
expect(cm.reload.migration_settings[:job_ids]).to eq([123])
end
it "goes through instfs if enabled" do
cm = setup_zip_import(@course)
allow(InstFS).to receive(:enabled?).and_return(true)