Class: Fractor::Workflow::RetryConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/fractor/workflow/retry_config.rb

Overview

Configuration for job retry behavior

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(strategy: NoRetry.new, timeout: nil, retryable_errors: [StandardError]) ⇒ RetryConfig

Returns a new instance of RetryConfig.



11
12
13
14
15
16
17
18
19
# File 'lib/fractor/workflow/retry_config.rb', line 11

def initialize(
  strategy: NoRetry.new,
  timeout: nil,
  retryable_errors: [StandardError]
)
  @strategy = strategy
  @timeout = timeout
  @retryable_errors = Array(retryable_errors)
end

Instance Attribute Details

#retryable_errorsObject (readonly)

Returns the value of attribute retryable_errors.



9
10
11
# File 'lib/fractor/workflow/retry_config.rb', line 9

def retryable_errors
  @retryable_errors
end

#strategyObject (readonly)

Returns the value of attribute strategy.



9
10
11
# File 'lib/fractor/workflow/retry_config.rb', line 9

def strategy
  @strategy
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



9
10
11
# File 'lib/fractor/workflow/retry_config.rb', line 9

def timeout
  @timeout
end

Class Method Details

.create_strategy(**options) ⇒ RetryStrategy

Create a retry strategy from options

Parameters:

  • options (Hash)

    Strategy options

Returns:



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/fractor/workflow/retry_config.rb', line 62

def self.create_strategy(**options)
  backoff = options[:backoff] || :exponential
  max_attempts = options[:max_attempts] || 3
  max_delay = options[:max_delay]

  case backoff
  when :exponential
    ExponentialBackoff.new(
      initial_delay: options[:initial_delay] || 1,
      multiplier: options[:multiplier] || 2,
      max_attempts: max_attempts,
      max_delay: max_delay,
    )
  when :linear
    LinearBackoff.new(
      initial_delay: options[:initial_delay] || 1,
      increment: options[:increment] || 1,
      max_attempts: max_attempts,
      max_delay: max_delay,
    )
  when :constant
    ConstantDelay.new(
      delay: options[:delay] || 1,
      max_attempts: max_attempts,
      max_delay: max_delay,
    )
  when :none, false
    NoRetry.new
  else
    raise ArgumentError, "Unknown backoff strategy: #{backoff}"
  end
end

.from_options(**options) ⇒ RetryConfig

Create a retry config from a hash of options

Parameters:

  • options (Hash)

    Configuration options

Options Hash (**options):

  • :backoff (Symbol)

    Strategy type (:exponential, :linear, :constant, :none)

  • :max_attempts (Integer)

    Maximum retry attempts

  • :initial_delay (Numeric)

    Initial delay in seconds

  • :max_delay (Numeric)

    Maximum delay in seconds

  • :timeout (Numeric)

    Job timeout in seconds

  • :retryable_errors (Array<Class>)

    List of retryable error classes

Returns:



50
51
52
53
54
55
56
57
# File 'lib/fractor/workflow/retry_config.rb', line 50

def self.from_options(**options)
  strategy = create_strategy(**options)
  new(
    strategy: strategy,
    timeout: options[:timeout],
    retryable_errors: options[:retryable_errors] || [StandardError],
  )
end

Instance Method Details

#delay_for(attempt) ⇒ Numeric

Calculate delay for a given attempt

Parameters:

  • attempt (Integer)

    The attempt number

Returns:

  • (Numeric)

    Delay in seconds



37
38
39
# File 'lib/fractor/workflow/retry_config.rb', line 37

def delay_for(attempt)
  strategy.delay_for(attempt)
end

#max_attemptsInteger

Get maximum number of retry attempts

Returns:

  • (Integer)

    Maximum attempts



30
31
32
# File 'lib/fractor/workflow/retry_config.rb', line 30

def max_attempts
  strategy.max_attempts
end

#retryable?(error) ⇒ Boolean

Check if an error should trigger a retry

Parameters:

  • error (Exception)

    The error to check

Returns:

  • (Boolean)

    true if error should be retried



24
25
26
# File 'lib/fractor/workflow/retry_config.rb', line 24

def retryable?(error)
  retryable_errors.any? { |err_class| error.is_a?(err_class) }
end