Class: SimpleConnect::Retryable

Inherits:
Object
  • Object
show all
Defined in:
lib/simple_connect/retryable.rb

Overview

Library-level retry policy for transient transport failures (5xx, network errors). Lives next to ‘Request`; `Client.new(max_attempts: N)` is the ergonomic knob, and power users can pass a custom instance via `retryable:` for exponential backoff / jitter / caps.

Use ‘max_attempts: 1` to disable retries entirely — appropriate when `events.deliver` is wrapped in a job queue (Sidekiq, ActiveJob) that has its own retry layer. Avoids double-retry math (1 job retry × 3 lib retries = 75 HTTP calls per logical failure).

Constant Summary collapse

DEFAULT_MAX_ATTEMPTS =
3

Instance Method Summary collapse

Constructor Details

#initialize(max_attempts: DEFAULT_MAX_ATTEMPTS, delay: ->(n) { n.to_f }, sleep: Kernel.method(:sleep)) ⇒ Retryable

Returns a new instance of Retryable.

Parameters:

  • max_attempts (Integer) (defaults to: DEFAULT_MAX_ATTEMPTS)

    total attempts (1 = no retries).

  • delay (#call) (defaults to: ->(n) { n.to_f })

    lambda/proc taking the attempt number (1-indexed), returning seconds to sleep before the next attempt. Default is linear: 1s, 2s.

  • sleep (#call) (defaults to: Kernel.method(:sleep))

    sleep function. Injectable for specs so the suite doesn’t actually wait.

Raises:

  • (ArgumentError)


22
23
24
25
26
27
28
# File 'lib/simple_connect/retryable.rb', line 22

def initialize(max_attempts: DEFAULT_MAX_ATTEMPTS, delay: ->(n) { n.to_f }, sleep: Kernel.method(:sleep))
  raise ArgumentError, "max_attempts must be >= 1" if max_attempts < 1

  @max_attempts = max_attempts
  @delay        = delay
  @sleep        = sleep
end

Instance Method Details

#call(retriable_if:) ⇒ Object

Call the block up to ‘max_attempts` times. The block receives the 1-indexed attempt number and must return an object responding to `#success?`. `retriable_if` decides whether a failed result is retryable (5xx / network → yes; 4xx → no).



34
35
36
37
38
39
40
41
42
43
# File 'lib/simple_connect/retryable.rb', line 34

def call(retriable_if:)
  attempt = 0
  loop do
    attempt += 1
    result   = yield(attempt)
    return result if result.success? || !retriable_if.call(result) || attempt >= @max_attempts

    @sleep.call(@delay.call(attempt))
  end
end