Class: LazyData::Retries

Inherits:
Object
  • Object
show all
Defined in:
lib/lazy_data/retries.rb

Overview

A simple retry manager with optional delay and backoff. It retries until either a configured maximum number of attempts has been reached, or a configurable total time has elapsed since the first failure.

This class is not thread-safe by itself. Access should be protected by an external mutex.

Instance Method Summary collapse

Constructor Details

#initialize(max_tries: 1, max_time: nil, initial_delay: 0, max_delay: nil, delay_multiplier: 1, delay_adder: 0, delay_includes_time_elapsed: false) ⇒ Retries

Create and initialize a retry manager.

Parameters:

  • max_tries (Integer, nil) (defaults to: 1)

    Maximum number of attempts before we give up altogether, or nil for no maximum. Default is 1, indicating one attempt and no retries.

  • max_time (Numeric, nil) (defaults to: nil)

    The maximum amount of time in seconds until we give up altogether, or nil for no maximum. Default is nil.

  • initial_delay (Numeric) (defaults to: 0)

    Initial delay between attempts, in seconds. Default is 0.

  • max_delay (Numeric, nil) (defaults to: nil)

    Maximum delay between attempts, in seconds, or nil for no max. Default is nil.

  • delay_multiplier (Numeric) (defaults to: 1)

    Multipler applied to the delay between attempts. Default is 1 for no change.

  • delay_adder (Numeric) (defaults to: 0)

    Value added to the delay between attempts. Default is 0 for no change.

  • delay_includes_time_elapsed (true, false) (defaults to: false)

    Whether to deduct any time already elapsed from the retry delay. Default is false.

Raises:

  • (::ArgumentError)


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/lazy_data/retries.rb', line 49

def initialize(max_tries: 1,
               max_time: nil,
               initial_delay: 0,
               max_delay: nil,
               delay_multiplier: 1,
               delay_adder: 0,
               delay_includes_time_elapsed: false)
  @max_tries = max_tries&.to_i
  raise ::ArgumentError, "max_tries must be positive" if @max_tries && !@max_tries.positive?
  @max_time = max_time
  raise ::ArgumentError, "max_time must be positive" if @max_time && !@max_time.positive?
  @initial_delay = initial_delay
  raise ::ArgumentError, "initial_delay must be nonnegative" if @initial_delay&.negative?
  @max_delay = max_delay
  raise ::ArgumentError, "max_delay must be nonnegative" if @max_delay&.negative?
  @delay_multiplier = delay_multiplier
  @delay_adder = delay_adder
  @delay_includes_time_elapsed = delay_includes_time_elapsed
  reset!
end

Instance Method Details

#finish!self

Cause the retry limit to be reached immediately.

Returns:

  • (self)


109
110
111
112
# File 'lib/lazy_data/retries.rb', line 109

def finish!
  @current_delay = nil
  self
end

#finished?true, false

Returns true if the retry limit has been reached.

Returns:

  • (true, false)


90
91
92
# File 'lib/lazy_data/retries.rb', line 90

def finished?
  @current_delay.nil?
end

#next(start_time: nil) ⇒ Numeric?

Advance to the next attempt.

Returns nil if the retry limit has been reached. Otherwise, returns the delay in seconds until the next retry (0 for no delay). Raises an error if the previous call already returned nil.

Parameters:

  • start_time (Numeric, nil) (defaults to: nil)

    Optional start time in monotonic time units. Used if delay_includes_time_elapsed is set.

Returns:

  • (Numeric, nil)


125
126
127
128
129
130
131
132
133
134
135
# File 'lib/lazy_data/retries.rb', line 125

def next(start_time: nil)
  raise "no tries remaining" if finished?
  cur_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
  if @current_delay == :reset
    setup_first_retry(cur_time)
  else
    advance_delay
  end
  advance_retry(cur_time)
  adjusted_delay(start_time, cur_time)
end

#reset!self

Reset to the initial attempt.

Returns:

  • (self)


99
100
101
102
# File 'lib/lazy_data/retries.rb', line 99

def reset!
  @current_delay = :reset
  self
end

#reset_dupRetries

Create a duplicate in the reset state

Returns:



75
76
77
78
79
80
81
82
83
# File 'lib/lazy_data/retries.rb', line 75

def reset_dup
  Retries.new(max_tries: @max_tries,
              max_time: @max_time,
              initial_delay: @initial_delay,
              max_delay: @max_delay,
              delay_multiplier: @delay_multiplier,
              delay_adder: @delay_adder,
              delay_includes_time_elapsed: @delay_includes_time_elapsed)
end