calculate enrollment states after transaction

fixes CORE-2730

test plan
 - run sis import the deletes users with
   enrollments
 - restore sis import
 - the enrollments should have the correct state
   on the users page

Change-Id: I3f25ea56f3c033e522e891276befbcab3edb09ea
Reviewed-on: https://gerrit.instructure.com/188190
Tested-by: Jenkins
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Rob Orton <rob@instructure.com>
This commit is contained in:
Rob Orton 2019-04-03 11:55:35 -06:00
parent 24f4de9525
commit 71ffb3d532
3 changed files with 20 additions and 13 deletions

View File

@ -188,20 +188,15 @@ class Enrollment::BatchStateUpdater
# this is to be used for enrollments that just changed workflow_states but are
# not deleted. This also skips notifying users.
def self.run_call_backs_for(batch)
def self.run_call_backs_for(batch, root_account=nil)
raise ArgumentError, 'Cannot call with more than 1000 enrollments' if batch.count > 1_000
return if batch.empty?
Enrollment.transaction do
students = Enrollment.of_student_type.where(id: batch).preload({user: :linked_observers}, :root_account).to_a
user_ids = Enrollment.where(id: batch).distinct.pluck(:user_id)
courses = Course.where(id: Enrollment.where(id: batch).select(:course_id).distinct).to_a
root_account = courses.first.root_account
EnrollmentState.send_later_if_production_enqueue_args(
:force_recalculation,
{run_at: 1.minute.from_now,
n_strand: "restore_states_enrollment_states:#{root_account.global_id}}",
max_attempts: 2},
batch
)
root_account ||= courses.first.root_account
return unless root_account
touch_and_update_associations(user_ids)
update_linked_enrollments(students)
needs_grading_count_updated(courses)
@ -209,5 +204,14 @@ class Enrollment::BatchStateUpdater
update_cached_due_dates(students, root_account)
touch_all_graders_if_needed(students)
end
root_account ||= Enrollment.where(id: batch).take&.root_account
return unless root_account
EnrollmentState.send_later_if_production_enqueue_args(
:force_recalculation,
{run_at: Setting.get("wait_time_to_calculate_enrollment_state", 1).to_f.minute.from_now,
n_strand: ["restore_states_enrollment_states", root_account.global_id],
max_attempts: 2},
batch
)
end
end

View File

@ -770,7 +770,6 @@ class SisBatch < ActiveRecord::Base
end
def restore_workflow_states(scope, type, restore_progress, count, total)
count = 0
Shackles.activate(:slave) do
scope.active.order(:context_id).find_in_batches(batch_size: 5_000) do |data|
Shackles.activate(:master) do
@ -780,7 +779,7 @@ class SisBatch < ActiveRecord::Base
ids = type.constantize.connection.select_values(restore_sql(type, data.map(&:to_restore_array)))
if type == 'Enrollment'
ids.each_slice(1000) do |slice|
Enrollment::BatchStateUpdater.send_later_enqueue_args(:run_call_backs_for, {n_strand: "restore_states_batch_updater:#{account.global_id}}"}, slice)
Enrollment::BatchStateUpdater.send_later_enqueue_args(:run_call_backs_for, {n_strand: ["restore_states_batch_updater", account.global_id]}, slice, self.account)
end
end
count += update_restore_progress(restore_progress, data, count, total)
@ -799,7 +798,7 @@ class SisBatch < ActiveRecord::Base
end
end
successful_ids.each_slice(1000) do |slice|
Enrollment::BatchStateUpdater.send_later_enqueue_args(:run_call_backs_for, {n_strand: "restore_states_batch_updater:#{account.global_id}}"}, slice)
Enrollment::BatchStateUpdater.send_later_enqueue_args(:run_call_backs_for, {n_strand: ["restore_states_batch_updater", account.global_id]}, slice, self.account)
end
count += update_restore_progress(restore_progress, data - failed_data, count, total)
roll_back_data.active.where(id: failed_data).update_all(workflow_state: 'failed', updated_at: Time.zone.now)
@ -815,7 +814,7 @@ class SisBatch < ActiveRecord::Base
self.shard.activate do
restore_progress = Progress.create! context: self, tag: "sis_batch_state_restore", completion: 0.0
restore_progress.process_job(self, :restore_states_for_batch,
{n_strand: "restore_states_for_batch:#{account.global_id}}"},
{n_strand: ["restore_states_for_batch", account.global_id]},
{batch_mode: batch_mode, undelete_only: undelete_only, unconclude_only: unconclude_only})
restore_progress
end

View File

@ -24,6 +24,10 @@ describe "Enrollment::BatchStateUpdater" do
to raise_error(ArgumentError, 'Cannot call with more than 1000 enrollments')
end
it 'should not fail with more than empty batch' do
expect { Enrollment::BatchStateUpdater.run_call_backs_for([], nil) }.to_not raise_error
end
before(:once) do
@enrollment2 = course_with_teacher(active_all: true)
@user2 = @enrollment2.user