BigW Consortium Gitlab

forbid_sidekiq_in_transactions.rb 1.46 KB
Newer Older
1 2
module Sidekiq
  module Worker
Douwe Maan committed
3 4 5 6 7 8 9 10 11 12
    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
13

14 15 16 17 18 19
    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|
Douwe Maan committed
20
            return super(*args) if Sidekiq::Worker.skip_transaction_check
21
            return super(*args) unless ActiveRecord::Base.connection.open_transactions > NESTING
22

23 24 25 26
            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.
27

28 29
              Use an `after_commit` hook, or include `AfterCommitQueue` and use a `run_after_commit` block instead.
            MSG
30 31 32 33 34 35 36 37
          end
        end
      end

      prepend NoSchedulingFromTransactions
    end
  end
end
38 39 40

module ActiveRecord
  class Base
Douwe Maan committed
41
    module SkipTransactionCheckAfterCommit
42
      def committed!(*)
Douwe Maan committed
43
        Sidekiq::Worker.skipping_transaction_check { super }
44 45 46
      end
    end

Douwe Maan committed
47
    prepend SkipTransactionCheckAfterCommit
48 49
  end
end