Module: ActiveRecordDeadlockHandler::RetryExecutor

Defined in:
lib/active_record_deadlock_handler/retry_executor.rb

Constant Summary collapse

RETRYABLE_ERRORS =
[ActiveRecord::Deadlocked].freeze

Class Method Summary collapse

Class Method Details

.run(config: ActiveRecordDeadlockHandler.configuration, &block) ⇒ Object

Executes the given block, retrying on deadlock errors with exponential backoff.

Thread-safe: all state (attempt counter, delay) is local to the call stack.

Parameters:

  • config (Configuration) (defaults to: ActiveRecordDeadlockHandler.configuration)

Yield Returns:

  • (Object)

    the return value of the block on success

Raises:

  • (ActiveRecord::Deadlocked)

    if max_retries is exhausted and reraise_after_exhaustion is true



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/active_record_deadlock_handler/retry_executor.rb', line 14

def self.run(config: ActiveRecordDeadlockHandler.configuration, &block)
  attempt = 0

  begin
    attempt += 1
    yield
  rescue *RETRYABLE_ERRORS => e
    Callbacks.run(exception: e, attempt: attempt, config: config)

    if attempt <= config.max_retries
      Logging.log("Deadlock detected, retrying...", exception: e, attempt: attempt, config: config)
      delay = Backoff.compute(attempt: attempt, config: config)
      sleep(delay)
      retry
    else
      Logging.log(
        "Deadlock detected, max retries (#{config.max_retries}) exhausted.",
        exception: e,
        attempt: attempt,
        config: config
      )
      raise if config.reraise_after_exhaustion
    end
  end
end