debian-mirror-gitlab/config/initializers/forbid_sidekiq_in_transactions.rb

56 lines
1.7 KiB
Ruby
Raw Normal View History

2017-09-10 17:25:29 +05:30
module Sidekiq
module Worker
2018-03-17 18:26:18 +05:30
EnqueueFromTransactionError = Class.new(StandardError)
2017-09-10 17:25:29 +05:30
mattr_accessor :skip_transaction_check
self.skip_transaction_check = false
def self.skipping_transaction_check(&block)
skip_transaction_check = self.skip_transaction_check
self.skip_transaction_check = true
yield
ensure
self.skip_transaction_check = skip_transaction_check
end
module ClassMethods
2018-03-17 18:26:18 +05:30
module NoEnqueueingFromTransactions
2017-09-10 17:25:29 +05:30
%i(perform_async perform_at perform_in).each do |name|
define_method(name) do |*args|
2018-03-17 18:26:18 +05:30
if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction?
begin
raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG
`#{self}.#{name}` cannot be called inside a transaction as this can lead to
race conditions when the worker runs before the transaction is committed and
tries to access a model that has not been saved yet.
Use an `after_commit` hook, or include `AfterCommitQueue` and use a `run_after_commit` block instead.
MSG
rescue Sidekiq::Worker::EnqueueFromTransactionError => e
2018-10-15 14:42:47 +05:30
::Rails.logger.error(e.message) if ::Rails.env.production?
Gitlab::Sentry.track_exception(e)
2018-03-17 18:26:18 +05:30
end
end
super(*args)
2017-09-10 17:25:29 +05:30
end
end
end
2018-03-17 18:26:18 +05:30
prepend NoEnqueueingFromTransactions
2017-09-10 17:25:29 +05:30
end
end
end
module ActiveRecord
class Base
module SkipTransactionCheckAfterCommit
def committed!(*)
Sidekiq::Worker.skipping_transaction_check { super }
end
end
prepend SkipTransactionCheckAfterCommit
end
end