Class: Ksef::RetryPolicy

Inherits:
Data
  • Object
show all
Defined in:
lib/ksef/retry_policy.rb,
lib/ksef/retry_policy.rb

Overview

Behaviour for RetryPolicy.

Constant Summary collapse

IDEMPOTENT_METHODS =

Methods with no side effects, so replaying them is safe.

%i[get head].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#backoff_factorObject (readonly)

Returns the value of attribute backoff_factor

Returns:

  • (Object)

    the current value of backoff_factor



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def backoff_factor
  @backoff_factor
end

#base_intervalObject (readonly)

Returns the value of attribute base_interval

Returns:

  • (Object)

    the current value of base_interval



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def base_interval
  @base_interval
end

#max_attemptsObject (readonly)

Returns the value of attribute max_attempts

Returns:

  • (Object)

    the current value of max_attempts



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def max_attempts
  @max_attempts
end

#max_intervalObject (readonly)

Returns the value of attribute max_interval

Returns:

  • (Object)

    the current value of max_interval



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def max_interval
  @max_interval
end

#max_retry_afterObject (readonly)

Returns the value of attribute max_retry_after

Returns:

  • (Object)

    the current value of max_retry_after



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def max_retry_after
  @max_retry_after
end

#respect_retry_afterObject (readonly)

Returns the value of attribute respect_retry_after

Returns:

  • (Object)

    the current value of respect_retry_after



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def respect_retry_after
  @respect_retry_after
end

#retry_statusesObject (readonly)

Returns the value of attribute retry_statuses

Returns:

  • (Object)

    the current value of retry_statuses



12
13
14
# File 'lib/ksef/retry_policy.rb', line 12

def retry_statuses
  @retry_statuses
end

Class Method Details

.defaultObject



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/ksef/retry_policy.rb', line 28

def default
  new(
    max_attempts: 3,
    base_interval: 1.0,
    max_interval: 30.0,
    max_retry_after: 60.0,
    backoff_factor: 2.0,
    retry_statuses: [429, 500, 502, 503, 504].freeze,
    respect_retry_after: true
  )
end

.noneObject

Disable retries entirely.



41
42
43
# File 'lib/ksef/retry_policy.rb', line 41

def none
  default.with(max_attempts: 1)
end

Instance Method Details

#interval_for(attempt:, retry_after: nil) ⇒ Object

Seconds to wait before the next attempt.

Retry-After wins over the computed backoff, and is deliberately not clamped to max_interval: on 429 the block period is dynamic and lengthens with repeat offences, so retrying earlier than the server asked makes things strictly worse (docs/REFERENCE.md ยง6). max_retry_after bounds this instead, by declining the retry outright in #retryable?.

Parameters:

  • attempt (Integer)

    1-based

  • retry_after (Integer, Float, nil) (defaults to: nil)

    seconds, from the Retry-After header



71
72
73
74
75
# File 'lib/ksef/retry_policy.rb', line 71

def interval_for(attempt:, retry_after: nil)
  return retry_after.to_f if respect_retry_after && retry_after

  [base_interval * (backoff_factor**(attempt - 1)), max_interval].min
end

#retryable?(method:, status:, attempt: 1, retry_after: nil) ⇒ Boolean

Parameters:

  • method (Symbol)

    the HTTP verb, lowercase

  • status (Integer, nil)

    the response status, or nil for a transport failure

  • attempt (Integer) (defaults to: 1)

    1-based

  • retry_after (Integer, Float, nil) (defaults to: nil)

    seconds, from the Retry-After header

Returns:

  • (Boolean)


50
51
52
53
54
55
56
57
58
59
# File 'lib/ksef/retry_policy.rb', line 50

def retryable?(method:, status:, attempt: 1, retry_after: nil)
  return false if attempt >= max_attempts
  return false unless IDEMPOTENT_METHODS.include?(method.to_s.downcase.to_sym)
  # Waiting less than the server demanded provokes a longer block, so if we are not
  # prepared to wait the full period we must not retry at all.
  return false if respect_retry_after && retry_after && retry_after.to_f > max_retry_after
  return true if status.nil? # connection reset / timeout on an idempotent request

  retry_statuses.include?(status)
end