Module: Sidekiq::TransactionGuard

Defined in:
lib/sidekiq/transaction_guard.rb,
lib/sidekiq/transaction_guard/railtie.rb,
lib/sidekiq/transaction_guard/version.rb,
lib/sidekiq/transaction_guard/minitest.rb,
lib/sidekiq/transaction_guard/middleware.rb,
lib/sidekiq/transaction_guard/database_cleaner.rb

Defined Under Namespace

Modules: DatabaseCleaner, MinitestHelper Classes: InsideTransactionError, Middleware, Railtie

Constant Summary collapse

VALID_MODES =
[:warn, :stderr, :error, :disabled].freeze
VERSION =
File.read(File.expand_path("../../../../VERSION", __FILE__)).chomp.freeze

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.modeSymbol

Return the current mode.

Returns:

  • (Symbol)


58
59
60
# File 'lib/sidekiq/transaction_guard.rb', line 58

def mode
  @mode
end

Class Method Details

.add_connection_class(connection_class) ⇒ void

This method returns an undefined value.

Add a class that maintains its own connection pool to the connections being monitored for open transactions. You don’t need to add ‘ActiveRecord::Base` or subclasses. Only the base class that establishes a new connection pool with a call to `establish_connection` needs to be added.

Parameters:

  • connection_class (Class)

    an ActiveRecord model class with its own connection pool



84
85
86
# File 'lib/sidekiq/transaction_guard.rb', line 84

def add_connection_class(connection_class)
  @lock.synchronize { @connection_classes << connection_class }
end

.connection_classesArray<Class>

Return the classes that have been added via ‘add_connection_class`.

Returns:

  • (Array<Class>)


91
92
93
# File 'lib/sidekiq/transaction_guard.rb', line 91

def connection_classes
  ([ActiveRecord::Base] + @lock.synchronize { @connection_classes.to_a }).uniq
end

.disable { ... } ⇒ Object

Disable the transaction guard within the provided block. This is useful in test environments when you want to setup data for your tests without worrying about transaction levels.

Yields:

  • the block to execute with the transaction guard disabled

Returns:

  • (Object)

    the return value of the block



115
116
117
118
119
120
121
122
123
# File 'lib/sidekiq/transaction_guard.rb', line 115

def disable
  save_mode = mode
  begin
    self.mode = :disabled
    yield
  ensure
    self.mode = save_mode
  end
end

.in_transaction?Boolean

Return true if any connection is currently inside of a transaction.

Returns:

  • (Boolean)


98
99
100
101
102
103
104
105
106
107
108
# File 'lib/sidekiq/transaction_guard.rb', line 98

def in_transaction?
  connection_classes.any? do |connection_class|
    connection_pool = connection_class.connection_pool
    connection = connection_class.connection if connection_pool.active_connection?
    if connection
      connection.open_transactions > allowed_transaction_level(connection_class)
    else
      false
    end
  end
end

.init(mode: nil) ⇒ void

This method returns an undefined value.

Helper method to add the client middleware to Sidekiq.



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/sidekiq/transaction_guard.rb', line 25

def init(mode: nil)
  self.mode = mode if mode

  Sidekiq.configure_client do |config|
    config.client_middleware do |chain|
      unless chain.exists?(Sidekiq::TransactionGuard::Middleware)
        chain.add Sidekiq::TransactionGuard::Middleware
      end
    end
  end
end

.notify {|Hash| ... } ⇒ void

This method returns an undefined value.

Define the global notify block. This block will be called with a Sidekiq job hash for all jobs enqueued inside transactions if the mode is ‘:warn` or `:stderr`.

Yields:

  • (Hash)

    the Sidekiq job hash



66
67
68
# File 'lib/sidekiq/transaction_guard.rb', line 66

def notify(&block)
  @notify = block
end

.notify_blockProc?

Return the block set as the notify handler with a call to ‘notify`.

Returns:

  • (Proc, nil)

    the notify block, or nil if none has been set



73
74
75
# File 'lib/sidekiq/transaction_guard.rb', line 73

def notify_block
  @notify
end

.set_allowed_transaction_level(connection_classes, base_transaction_level = 0) ⇒ void

This method returns an undefined value.

This method needs to be called to set the allowed transaction level for a connection class (see ‘add_connection_class` for more info). The current transaction level for that class’s connection will be set as the zero point. This method can only be called inside a block wrapped with the ‘testing` method.

Parameters:

  • connection_classes (Class, Array<Class>, Symbol)

    the connection class(es) to set the allowed transaction level for. If ‘:all` is provided, set the allowed transaction level for all connection classes set via `add_connection_class`.

  • base_transaction_level (Integer) (defaults to: 0)

    if provided, increment the allowed transaction level by this amount. This is used when using transactional fixtures to ignore the transaction opened within the test setup.



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/sidekiq/transaction_guard.rb', line 156

def set_allowed_transaction_level(connection_classes, base_transaction_level = 0)
  connection_counts = Thread.current[:sidekiq_rails_transaction_guard]
  unless connection_counts
    raise("set_allowed_transaction_level is only allowed inside a testing block")
  end

  connection_classes = self.connection_classes if connection_classes == :all
  Array(connection_classes).each do |connection_class|
    class_count = connection_class.connection.open_transactions + base_transaction_level
    connection_counts[connection_class.name] = class_count
  end
end

.testing { ... } ⇒ Object

This method call needs to be wrapped around tests that use transactional fixtures. It sets up data structures used to track the number of open transactions. The current transaction level is automatically captured as the baseline so that any transactions opened by test setup (e.g. transactional fixtures) are ignored.

Yields:

  • the test block to execute

Returns:

  • (Object)

    the return value of the block



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/sidekiq/transaction_guard.rb', line 132

def testing
  var = :sidekiq_rails_transaction_guard
  save_val = Thread.current[var]
  begin
    Thread.current[var] = (save_val ? save_val.dup : {})
    set_allowed_transaction_level(:all)
    yield
  ensure
    Thread.current[var] = save_val
  end
end