Follow up - 2c8825b387 - ActiveJobLock PG::TRSerializationFailure exception is actually ActiveRecord::SerializationFailure.

This commit is contained in:
Thorsten Eckel 2019-11-23 10:44:23 +01:00
parent 5c6bc72d1b
commit 3d00f4d25b
2 changed files with 19 additions and 21 deletions

View file

@ -89,12 +89,12 @@ module HasActiveJobLock
ActiveJobLock.transaction(isolation: :serializable) do ActiveJobLock.transaction(isolation: :serializable) do
yield yield
end end
# PostgeSQL prevents locking on records that are already locked rescue ActiveRecord::SerializationFailure => e
# for UPDATE in Serializable Isolation Level transactions, # PostgeSQL prevents locking on records that are already locked
# but it's safe to retry as described in the docs: # for UPDATE in Serializable Isolation Level transactions,
# https://www.postgresql.org/docs/10/transaction-iso.html # but it's safe to retry as described in the docs:
rescue PG::TRSerializationFailure # https://www.postgresql.org/docs/10/transaction-iso.html
retry e.message.include?('PG::TRSerializationFailure') ? retry : raise
rescue ActiveRecord::RecordNotUnique rescue ActiveRecord::RecordNotUnique
existing_active_job_lock! existing_active_job_lock!
end end

View file

@ -101,26 +101,24 @@ RSpec.describe HasActiveJobLock, type: :job do
end end
end end
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' context "when ActiveRecord::SerializationFailure 'PG::TRSerializationFailure: ERROR: could not serialize access due to concurrent update' is raised" do
context "when PG::TRSerializationFailure 'Could not serialize access due to concurrent update' is raised" do
it 'retries execution until succeed' do it 'retries execution until succeed' do
allow(ActiveRecord::Base.connection).to receive(:open_transactions).and_return(0) allow(ActiveRecord::Base.connection).to receive(:open_transactions).and_return(0)
allow(ActiveJobLock).to receive(:transaction).and_call_original allow(ActiveJobLock).to receive(:transaction).and_call_original
exception_raised = false exception_raised = false
allow(ActiveJobLock).to receive(:transaction).with(isolation: :serializable) do |&block| allow(ActiveJobLock).to receive(:transaction).with(isolation: :serializable) do |&block|
if !exception_raised if !exception_raised
exception_raised = true exception_raised = true
raise PG::TRSerializationFailure, 'Could not serialize access due to concurrent update' raise ActiveRecord::SerializationFailure, 'PG::TRSerializationFailure: ERROR: could not serialize access due to concurrent update'
end
block.call
end end
expect { job_class.perform_later }.to have_enqueued_job(job_class).exactly(:once) block.call
expect(exception_raised).to be true
end end
expect { job_class.perform_later }.to have_enqueued_job(job_class).exactly(:once)
expect(exception_raised).to be true
end end
end end
end end