diff --git a/app/jobs/concerns/has_active_job_lock.rb b/app/jobs/concerns/has_active_job_lock.rb index 57d784957..9931a4c11 100644 --- a/app/jobs/concerns/has_active_job_lock.rb +++ b/app/jobs/concerns/has_active_job_lock.rb @@ -89,12 +89,12 @@ module HasActiveJobLock ActiveJobLock.transaction(isolation: :serializable) do yield end - # PostgeSQL prevents locking on records that are already locked - # for UPDATE in Serializable Isolation Level transactions, - # but it's safe to retry as described in the docs: - # https://www.postgresql.org/docs/10/transaction-iso.html - rescue PG::TRSerializationFailure - retry + rescue ActiveRecord::SerializationFailure => e + # PostgeSQL prevents locking on records that are already locked + # for UPDATE in Serializable Isolation Level transactions, + # but it's safe to retry as described in the docs: + # https://www.postgresql.org/docs/10/transaction-iso.html + e.message.include?('PG::TRSerializationFailure') ? retry : raise rescue ActiveRecord::RecordNotUnique existing_active_job_lock! end diff --git a/spec/jobs/concerns/has_active_job_lock_spec.rb b/spec/jobs/concerns/has_active_job_lock_spec.rb index d7354eeae..4e8ae77e5 100644 --- a/spec/jobs/concerns/has_active_job_lock_spec.rb +++ b/spec/jobs/concerns/has_active_job_lock_spec.rb @@ -101,26 +101,24 @@ RSpec.describe HasActiveJobLock, type: :job do end end - if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' - context "when PG::TRSerializationFailure 'Could not serialize access due to concurrent update' is raised" do + context "when ActiveRecord::SerializationFailure 'PG::TRSerializationFailure: ERROR: could not serialize access due to concurrent update' is raised" do - it 'retries execution until succeed' do - allow(ActiveRecord::Base.connection).to receive(:open_transactions).and_return(0) - allow(ActiveJobLock).to receive(:transaction).and_call_original - exception_raised = false - allow(ActiveJobLock).to receive(:transaction).with(isolation: :serializable) do |&block| + it 'retries execution until succeed' do + allow(ActiveRecord::Base.connection).to receive(:open_transactions).and_return(0) + allow(ActiveJobLock).to receive(:transaction).and_call_original + exception_raised = false + allow(ActiveJobLock).to receive(:transaction).with(isolation: :serializable) do |&block| - if !exception_raised - exception_raised = true - raise PG::TRSerializationFailure, 'Could not serialize access due to concurrent update' - end - - block.call + if !exception_raised + exception_raised = true + raise ActiveRecord::SerializationFailure, 'PG::TRSerializationFailure: ERROR: could not serialize access due to concurrent update' end - expect { job_class.perform_later }.to have_enqueued_job(job_class).exactly(:once) - expect(exception_raised).to be true + block.call end + + expect { job_class.perform_later }.to have_enqueued_job(job_class).exactly(:once) + expect(exception_raised).to be true end end end