poc(batch_operation): track dossier processed safely

This commit is contained in:
Martin 2022-11-25 12:30:06 +01:00 committed by mfo
parent 7a51ecec5d
commit 4266ab93c5
3 changed files with 26 additions and 13 deletions

View file

@ -5,21 +5,11 @@ class BatchOperationProcessOneJob < ApplicationJob
success = true success = true
begin begin
batch_operation.process_one(dossier) batch_operation.process_one(dossier)
dossier.update(batch_operation: nil)
rescue => error rescue => error
success = false success = false
raise error raise error
ensure ensure
batch_operation.reload # reload before deciding if it has been finished batch_operation.track_dossier_processed(success, dossier)
batch_operation.run_at = Time.zone.now if batch_operation.called_for_first_time?
batch_operation.finished_at = Time.zone.now if batch_operation.called_for_last_time?
if success # beware to this one, will be refactored for stronger atomicity
batch_operation.success_dossier_ids.push(dossier.id)
batch_operation.failed_dossier_ids = batch_operation.failed_dossier_ids.reject { |d| d.dossier.id }
else
batch_operation.failed_dossier_ids.push(dossier.id)
end
batch_operation.save!
end end
end end
end end

View file

@ -31,6 +31,29 @@ class BatchOperation < ApplicationRecord
.map { |dossier| BatchOperationProcessOneJob.perform_later(self, dossier) } .map { |dossier| BatchOperationProcessOneJob.perform_later(self, dossier) }
end end
def track_dossier_processed(success, dossier)
transaction do
dossier.update(batch_operation: nil)
reload
manager = Arel::UpdateManager.new.table(arel_table).where(arel_table[:id].eq(id))
values = []
values.push([arel_table[:run_at], Time.zone.now]) if called_for_first_time?
values.push([arel_table[:finished_at], Time.zone.now]) if called_for_last_time?
if success
values.push([arel_table[:success_dossier_ids],Arel::Nodes::NamedFunction.new('array_append', [arel_table[:success_dossier_ids], dossier.id])])
values.push([arel_table[:failed_dossier_ids], Arel::Nodes::NamedFunction.new('array_remove', [arel_table[:failed_dossier_ids], dossier.id])])
else
values.push([arel_table[:failed_dossier_ids], Arel::Nodes::NamedFunction.new('array_append', [arel_table[:failed_dossier_ids], dossier.id])])
end
manager.set(values)
ActiveRecord::Base.connection.update(manager.to_sql)
end
end
def arel_table
BatchOperation.arel_table
end
def process_one(dossier) def process_one(dossier)
case operation case operation
when BatchOperation.operations.fetch(:archiver) when BatchOperation.operations.fetch(:archiver)

View file

@ -25,7 +25,7 @@ describe BatchOperationProcessOneJob, type: :job do
context 'when it succeed' do context 'when it succeed' do
it 'pushes dossier_job id to batch_operation.success_dossier_ids' do it 'pushes dossier_job id to batch_operation.success_dossier_ids' do
expect { subject.perform_now } expect { subject.perform_now }
.to change { batch_operation.success_dossier_ids } .to change { batch_operation.reload.success_dossier_ids }
.from([]) .from([])
.to([dossier_job.id]) .to([dossier_job.id])
end end
@ -44,7 +44,7 @@ describe BatchOperationProcessOneJob, type: :job do
run_at = 2.minutes.ago run_at = 2.minutes.ago
Timecop.freeze(run_at) do Timecop.freeze(run_at) do
expect { subject.perform_now } expect { subject.perform_now }
.to change { batch_operation.run_at } .to change { batch_operation.reload.run_at }
.from(nil) .from(nil)
.to(run_at) .to(run_at)
end end