Class: Yes::Core::Utils::ExponentialRetrier

Inherits:
Object
  • Object
show all
Defined in:
lib/yes/core/utils/exponential_retrier.rb

Overview

Generic exponential backoff retry utility Provides configurable retry logic with exponential backoff, jitter, and timeout

Defined Under Namespace

Classes: RetryFailedError, TimeoutError

Constant Summary collapse

DEFAULT_MAX_RETRIES =

Default configuration constants

6
DEFAULT_BASE_SLEEP_TIME =
0.1
DEFAULT_MAX_SLEEP_TIME =
5.0
DEFAULT_JITTER_FACTOR =
0.1
DEFAULT_TIMEOUT =
30

Instance Method Summary collapse

Constructor Details

#initialize(max_retries: DEFAULT_MAX_RETRIES, base_sleep_time: DEFAULT_BASE_SLEEP_TIME, max_sleep_time: DEFAULT_MAX_SLEEP_TIME, jitter_factor: DEFAULT_JITTER_FACTOR, timeout: DEFAULT_TIMEOUT, logger: nil) ⇒ ExponentialRetrier

Configuration for the retrier

Parameters:

  • max_retries (Integer) (defaults to: DEFAULT_MAX_RETRIES)

    Maximum number of retry attempts

  • base_sleep_time (Float) (defaults to: DEFAULT_BASE_SLEEP_TIME)

    Base sleep time in seconds for exponential backoff

  • max_sleep_time (Float) (defaults to: DEFAULT_MAX_SLEEP_TIME)

    Maximum sleep time to prevent excessive waiting

  • jitter_factor (Float) (defaults to: DEFAULT_JITTER_FACTOR)

    Jitter factor for randomizing sleep times

  • timeout (Integer) (defaults to: DEFAULT_TIMEOUT)

    Maximum time to wait before timing out

  • logger (Object) (defaults to: nil)

    Logger instance for retry information



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/yes/core/utils/exponential_retrier.rb', line 30

def initialize(
  max_retries: DEFAULT_MAX_RETRIES,
  base_sleep_time: DEFAULT_BASE_SLEEP_TIME,
  max_sleep_time: DEFAULT_MAX_SLEEP_TIME,
  jitter_factor: DEFAULT_JITTER_FACTOR,
  timeout: DEFAULT_TIMEOUT,
  logger: nil
)
  @max_retries = max_retries
  @base_sleep_time = base_sleep_time
  @max_sleep_time = max_sleep_time
  @jitter_factor = jitter_factor
  @timeout = timeout
  @logger = logger || (defined?(Rails) ? Rails.logger : nil)
  @start_time = Time.current
end

Instance Method Details

#call(condition_check:, action: nil, failure_message: nil, timeout_message: nil) { ... } ⇒ Object

Executes the retry logic with exponential backoff

Parameters:

  • condition_check (Proc)

    Block that returns true when condition is met

  • action (Proc) (defaults to: nil)

    Block to execute when condition is met

  • failure_message (String) (defaults to: nil)

    Custom failure message for RetryFailedError

  • timeout_message (String) (defaults to: nil)

    Custom timeout message for TimeoutError

Yields:

  • Alternative to action parameter - block to execute when condition is met

Returns:

  • (Object)

    Result of the action/block execution

Raises:



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/yes/core/utils/exponential_retrier.rb', line 57

def call(condition_check:, action: nil, failure_message: nil, timeout_message: nil, &block)
  action_block = action || block
  raise ArgumentError, 'Either action parameter or block must be provided' unless action_block

  attempts = 0
  total_wait_time = 0

  loop do
    check_timeout!(timeout_message)

    if condition_check.call
      log_success(attempts, total_wait_time) if attempts.positive?
      return action_block.call
    end

    attempts += 1
    if attempts >= max_retries
      log_failure(attempts, total_wait_time)
      raise RetryFailedError, failure_message || default_failure_message(attempts)
    end

    sleep_time = sleep_with_backoff(attempts)
    total_wait_time += sleep_time
  end
end