Class: ChronoForge::Executor::CompositeRetryPolicy

Inherits:
Object
  • Object
show all
Defined in:
lib/chrono_forge/executor/composite_retry_policy.rb

Overview

An ordered list of RetryPolicy objects, each scoped to an error type via its ‘retry_on`. On failure the first policy whose `retry_on` matches the raised error (by `is_a?`) is applied, giving each error type its own independent attempt budget and backoff curve. Put specific policies first and a catch-all (`retry_on: nil`) last; an unmatched error is not retried.

Pure: it never reads storage. The per-error count is supplied by the caller through the block passed to #retry_backoff, keyed by the matched policy’s budget_key (its declared errors).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(policies) ⇒ CompositeRetryPolicy

Returns a new instance of CompositeRetryPolicy.



15
16
17
18
19
20
# File 'lib/chrono_forge/executor/composite_retry_policy.rb', line 15

def initialize(policies)
  @policies = Array(policies)
  if @policies.empty?
    raise ArgumentError, "composite retry policy needs at least one policy"
  end
end

Instance Attribute Details

#policiesObject (readonly)

Returns the value of attribute policies.



13
14
15
# File 'lib/chrono_forge/executor/composite_retry_policy.rb', line 13

def policies
  @policies
end

Instance Method Details

#max_attemptsObject

Coarsest attempt bound across sub-policies, for the workflow-level safety-net guard. nil (unbounded) if any sub-policy is unbounded.



41
42
43
44
# File 'lib/chrono_forge/executor/composite_retry_policy.rb', line 41

def max_attempts
  caps = @policies.map(&:max_attempts)
  caps.include?(nil) ? nil : caps.max
end

#policy_for(error) ⇒ Object

First sub-policy whose retry_on matches the error, or nil.



23
24
25
# File 'lib/chrono_forge/executor/composite_retry_policy.rb', line 23

def policy_for(error)
  @policies.find { |p| p.matches?(error) }
end

#retry_backoff(error, attempts:) ⇒ Object

Routes on the live error and delegates the decision to the matched sub-policy. When a block is given it is called with the matched policy’s budget_key and must return that policy’s running attempt count (1-based, including the current failure); otherwise ‘attempts` is used.



31
32
33
34
35
36
37
# File 'lib/chrono_forge/executor/composite_retry_policy.rb', line 31

def retry_backoff(error, attempts:)
  sub = policy_for(error)
  return nil if sub.nil?

  count = block_given? ? yield(sub.budget_key) : attempts
  sub.retryable?(error, count) ? sub.backoff_for(count) : nil
end