Module: RubyLLM::Agents::Reliability

Defined in:
lib/ruby_llm/agents/infrastructure/reliability.rb

Overview

Reliability module providing error classes and utilities for retry/fallback logic

This module defines custom error types for reliability features and provides utilities for determining which errors are retryable.

Examples:

Checking if an error is retryable

Reliability.retryable_error?(Timeout::Error.new)  # => true
Reliability.retryable_error?(ArgumentError.new)   # => false

See Also:

Defined Under Namespace

Classes: AllModelsExhaustedError, BudgetExceededError, CircuitBreakerOpenError, Error, TotalTimeoutError

Class Method Summary collapse

Class Method Details

.calculate_backoff(strategy:, base:, max_delay:, attempt:) ⇒ Float

Calculates the backoff delay for a retry attempt

Parameters:

  • strategy (Symbol)

    The backoff strategy (:constant or :exponential)

  • base (Float)

    The base delay in seconds

  • max_delay (Float)

    The maximum delay in seconds

  • attempt (Integer)

    The current attempt number (0-indexed)

Returns:

  • (Float)

    The delay in seconds (including jitter)



227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 227

def calculate_backoff(strategy:, base:, max_delay:, attempt:)
  delay = case strategy
  when :constant
    base
  when :exponential
    [base * (2**attempt), max_delay].min
  else
    base
  end

  # Add jitter (0 to 50% of delay)
  jitter = rand * delay * 0.5
  delay + jitter
end

.default_non_fallback_errorsArray<Class>

Default list of error classes that should never trigger fallback

These errors indicate programming bugs that won’t be fixed by trying a different model. They should fail immediately.

Returns:

  • (Array<Class>)

    Error classes that are non-fallback by default



146
147
148
149
150
151
152
153
154
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 146

def default_non_fallback_errors
  @default_non_fallback_errors ||= [
    ArgumentError,
    TypeError,
    NameError,
    NoMethodError,
    NotImplementedError
  ]
end

.default_retryable_errorsArray<Class>

Default list of error classes that are considered retryable

These errors typically indicate transient issues that may resolve on retry.

Returns:

  • (Array<Class>)

    Error classes that are retryable by default



171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 171

def default_retryable_errors
  @default_retryable_errors ||= [
    Timeout::Error,
    defined?(Net::OpenTimeout) ? Net::OpenTimeout : nil,
    defined?(Net::ReadTimeout) ? Net::ReadTimeout : nil,
    defined?(Faraday::TimeoutError) ? Faraday::TimeoutError : nil,
    defined?(Faraday::ConnectionFailed) ? Faraday::ConnectionFailed : nil,
    defined?(Errno::ECONNREFUSED) ? Errno::ECONNREFUSED : nil,
    defined?(Errno::ECONNRESET) ? Errno::ECONNRESET : nil,
    defined?(Errno::ETIMEDOUT) ? Errno::ETIMEDOUT : nil,
    defined?(SocketError) ? SocketError : nil,
    defined?(OpenSSL::SSL::SSLError) ? OpenSSL::SSL::SSLError : nil
  ].compact
end

.non_fallback_error?(error, custom_errors: []) ⇒ Boolean

Determines if an error is a programming error that should not trigger fallback

Parameters:

  • error (Exception)

    The error to check

  • custom_errors (Array<Class>) (defaults to: [])

    Additional error classes to consider non-fallback

Returns:

  • (Boolean)

    true if the error should fail immediately



161
162
163
164
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 161

def non_fallback_error?(error, custom_errors: [])
  all = default_non_fallback_errors + Array(custom_errors)
  all.any? { |klass| error.is_a?(klass) }
end

.retryable_by_message?(error, custom_patterns: nil) ⇒ Boolean

Determines if an error is retryable based on its message content

Some errors (like HTTP 5xx responses) may not have specific error classes but can be identified by their message.

Parameters:

  • error (Exception)

    The error to check

  • custom_patterns (Array<String>, nil) (defaults to: nil)

    Additional patterns to check

Returns:

  • (Boolean)

    true if the error message indicates a retryable condition



206
207
208
209
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 206

def retryable_by_message?(error, custom_patterns: nil)
  message = error.message.to_s.downcase
  retryable_patterns(custom_patterns: custom_patterns).any? { |pattern| message.include?(pattern) }
end

.retryable_error?(error, custom_errors: [], custom_patterns: nil) ⇒ Boolean

Determines if an error is retryable based on default and custom error classes

Parameters:

  • error (Exception)

    The error to check

  • custom_errors (Array<Class>) (defaults to: [])

    Additional error classes to consider retryable

  • custom_patterns (Array<String>, nil) (defaults to: nil)

    Additional patterns to check in error messages

Returns:

  • (Boolean)

    true if the error is retryable



192
193
194
195
196
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 192

def retryable_error?(error, custom_errors: [], custom_patterns: nil)
  all_retryable = default_retryable_errors + Array(custom_errors)
  all_retryable.any? { |klass| error.is_a?(klass) } ||
    retryable_by_message?(error, custom_patterns: custom_patterns)
end

.retryable_patterns(custom_patterns: nil) ⇒ Array<String>

Patterns in error messages that indicate retryable errors

Parameters:

  • custom_patterns (Array<String>, nil) (defaults to: nil)

    Additional patterns to include

Returns:

  • (Array<String>)

    Patterns to match against error messages



215
216
217
218
# File 'lib/ruby_llm/agents/infrastructure/reliability.rb', line 215

def retryable_patterns(custom_patterns: nil)
  base = RubyLLM::Agents.configuration.all_retryable_patterns
  custom_patterns ? (base + Array(custom_patterns)).uniq : base
end