Module: R2::Retry
- Defined in:
- lib/r2/retry.rb
Overview
Automatic retries with exponential backoff.
Transient failures, such as brief network instabilities, are retried a limited number of times. The wait between the attempts grows exponentially and is capped, so the remote service has time to recover without making the user wait indefinitely.
Only the error classes informed as transient are retried; every other failure is raised immediately, preserving the domain error mapping.
Defined Under Namespace
Classes: Policy
Constant Summary collapse
- DEFAULT_MAX_ATTEMPTS =
Total number of attempts: the first execution plus the retries.
3- DEFAULT_BASE_DELAY =
Wait applied after the first failed attempt, in seconds.
0.5- DEFAULT_MAX_DELAY =
Upper limit of the wait between attempts, in seconds.
5.0- DEFAULT_SLEEPER =
Waiting strategy used when nothing else is provided.
->(seconds) { sleep(seconds) }
- DEFAULT_DESCRIPTION =
Description used in the diagnostics when the caller gives none.
"operation"
Class Method Summary collapse
-
.call(policy: Policy.new, retry_on: [], logger: nil, sleeper: nil, description: nil) { ... } ⇒ Object
Runs the block, retrying the transient failures it raises.
-
.retry_message(attempt, policy, description, error, delay) ⇒ String
Builds the diagnostic message of a retry.
-
.transient?(error, retry_on) ⇒ Boolean
Indicates whether an error is considered transient.
Class Method Details
.call(policy: Policy.new, retry_on: [], logger: nil, sleeper: nil, description: nil) { ... } ⇒ Object
Runs the block, retrying the transient failures it raises.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/r2/retry.rb', line 65 def self.call(policy: Policy.new, retry_on: [], logger: nil, sleeper: nil, description: nil) attempt = 0 description ||= DEFAULT_DESCRIPTION begin attempt += 1 yield rescue StandardError => e raise unless transient?(e, retry_on) && attempt < policy.max_attempts delay = policy.delay_for(attempt) logger&.debug((attempt, policy, description, e, delay)) (sleeper || DEFAULT_SLEEPER).call(delay) retry end end |
.retry_message(attempt, policy, description, error, delay) ⇒ String
Builds the diagnostic message of a retry.
99 100 101 102 103 |
# File 'lib/r2/retry.rb', line 99 def self.(attempt, policy, description, error, delay) "Retrying #{description} in #{delay}s (attempt #{attempt + 1} of " \ "#{policy.max_attempts}) after a transient failure: " \ "#{error.class}: #{error.}" end |
.transient?(error, retry_on) ⇒ Boolean
Indicates whether an error is considered transient.
87 88 89 |
# File 'lib/r2/retry.rb', line 87 def self.transient?(error, retry_on) retry_on.any? { |error_class| error.is_a?(error_class) } end |