diff options
author | Sean McGivern <sean@mcgivern.me.uk> | 2017-06-05 09:34:05 +0000 |
---|---|---|
committer | Sean McGivern <sean@mcgivern.me.uk> | 2017-06-05 09:34:05 +0000 |
commit | 3cc5e48668caf97588241001866fd42666b2f8f0 (patch) | |
tree | 03cf2c22213686fad5829b896f515ebe9beeef3c /config | |
parent | 3b39cf4e0c5d0ca680a40bb7232fee4f7fdfb02e (diff) | |
parent | 103b5bf60ba952e661b3e22d866cc64eed7358ee (diff) | |
download | gitlab-ce-3cc5e48668caf97588241001866fd42666b2f8f0.tar.gz |
Merge branch 'sidekiq-transaction' into 'master'
Forbid Sidekiq scheduling in transactions
Closes #27233
See merge request !9376
Diffstat (limited to 'config')
-rw-r--r-- | config/initializers/forbid_sidekiq_in_transactions.rb | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb new file mode 100644 index 00000000000..a78711fe599 --- /dev/null +++ b/config/initializers/forbid_sidekiq_in_transactions.rb @@ -0,0 +1,49 @@ +module Sidekiq + module Worker + 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 + module NoSchedulingFromTransactions + NESTING = ::Rails.env.test? ? 1 : 0 + + %i(perform_async perform_at perform_in).each do |name| + define_method(name) do |*args| + return super(*args) if Sidekiq::Worker.skip_transaction_check + return super(*args) unless ActiveRecord::Base.connection.open_transactions > NESTING + + raise <<-MSG.strip_heredoc + `#{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 + end + end + end + + prepend NoSchedulingFromTransactions + end + end +end + +module ActiveRecord + class Base + module SkipTransactionCheckAfterCommit + def committed!(*) + Sidekiq::Worker.skipping_transaction_check { super } + end + end + + prepend SkipTransactionCheckAfterCommit + end +end |