Class: Mistri::RetryPolicy
- Inherits:
-
Object
- Object
- Mistri::RetryPolicy
- Defined in:
- lib/mistri/retry_policy.rb
Overview
When a failed turn is worth retrying, and how long to wait. Transient failures (rate limits, overload, server errors, timeouts, dropped or truncated streams) retry with jittered exponential backoff, honoring the provider's retry-after when it sent one. Everything else — auth, invalid requests, our own bugs — fails fast.
attempts counts retries, not calls: attempts 3 means up to four requests.
Constant Summary collapse
- RETRYABLE_STATUSES =
[408, 429, 500, 502, 503, 504, 529].freeze
- RETRYABLE_TYPES =
%w[ProviderError RateLimitError OverloadedError ServerError TruncatedStream EmptyCompletion].freeze
- EMPTY_COMPLETION =
What retries see when a completion answers nothing at all.
{ "type" => "EmptyCompletion", "message" => "the provider returned an empty completion" }.freeze
Instance Attribute Summary collapse
-
#attempts ⇒ Object
readonly
Returns the value of attribute attempts.
-
#base ⇒ Object
readonly
Returns the value of attribute base.
-
#max_delay ⇒ Object
readonly
Returns the value of attribute max_delay.
Instance Method Summary collapse
- #delay(attempt, retry_after = nil) ⇒ Object
-
#error_for(message) ⇒ Object
The error a finished attempt carries: the provider's own error, or a synthesized one for a completion that answers nothing at all, which a retry usually clears.
-
#initialize(attempts: 3, base: 1.0, max_delay: 30.0) ⇒ RetryPolicy
constructor
A new instance of RetryPolicy.
- #retry?(error, attempt) ⇒ Boolean
-
#retryable?(error) ⇒ Boolean
error is the ErrorData hash from an errored message.
Constructor Details
#initialize(attempts: 3, base: 1.0, max_delay: 30.0) ⇒ RetryPolicy
Returns a new instance of RetryPolicy.
18 19 20 21 22 |
# File 'lib/mistri/retry_policy.rb', line 18 def initialize(attempts: 3, base: 1.0, max_delay: 30.0) @attempts = attempts @base = base @max_delay = max_delay end |
Instance Attribute Details
#attempts ⇒ Object (readonly)
Returns the value of attribute attempts.
16 17 18 |
# File 'lib/mistri/retry_policy.rb', line 16 def attempts @attempts end |
#base ⇒ Object (readonly)
Returns the value of attribute base.
16 17 18 |
# File 'lib/mistri/retry_policy.rb', line 16 def base @base end |
#max_delay ⇒ Object (readonly)
Returns the value of attribute max_delay.
16 17 18 |
# File 'lib/mistri/retry_policy.rb', line 16 def max_delay @max_delay end |
Instance Method Details
#delay(attempt, retry_after = nil) ⇒ Object
55 56 57 58 59 60 |
# File 'lib/mistri/retry_policy.rb', line 55 def delay(attempt, retry_after = nil) return retry_after.clamp(0.0, max_delay) if retry_after exponential = base * (2**(attempt - 1)) (exponential * rand(0.5..1.0)).clamp(0.0, max_delay) end |
#error_for(message) ⇒ Object
The error a finished attempt carries: the provider's own error, or a synthesized one for a completion that answers nothing at all, which a retry usually clears.
37 38 39 40 41 |
# File 'lib/mistri/retry_policy.rb', line 37 def error_for() return .error if .stop_reason == StopReason::ERROR EMPTY_COMPLETION if empty?() end |
#retry?(error, attempt) ⇒ Boolean
30 31 32 |
# File 'lib/mistri/retry_policy.rb', line 30 def retry?(error, attempt) attempt <= attempts && retryable?(error) end |
#retryable?(error) ⇒ Boolean
error is the ErrorData hash from an errored message. A status decides when present; otherwise only known-transient types retry, so schema violations and host bugs never loop.
46 47 48 49 50 51 52 53 |
# File 'lib/mistri/retry_policy.rb', line 46 def retryable?(error) return false unless error status = error["status"] return RETRYABLE_STATUSES.include?(status) if status RETRYABLE_TYPES.include?(error["type"]) end |