Manages retry logic with backoff strategies.
Handles:
- 429 rate limit responses with server-provided RetryInfo delay
- Transient 5xx errors with exponential backoff and jitter
- Network/transport errors with bounded retries
Coordinates with the rate limiter state to avoid double retries.
Summary
Functions
Calculate backoff duration for a given attempt.
Classify a response to determine retry behavior.
Execute a request function with retry handling.
Extract retry delay from a 429 error response.
Types
@type response_status() :: :success | :rate_limited | :transient | :permanent
@type retry_result() :: {:ok, term()} | {:error, {:rate_limited, DateTime.t(), map()}} | {:error, {:transient_failure, pos_integer(), term()}} | {:error, term()}
Functions
@spec calculate_backoff(pos_integer(), Gemini.RateLimiter.Config.t()) :: pos_integer()
Calculate backoff duration for a given attempt.
Uses exponential backoff with jitter: base 2^(attempt-1) (1 ± jitter)
@spec classify_response({:ok, term()} | {:error, term()}) :: response_status()
Classify a response to determine retry behavior.
Returns
:success- Request succeeded:rate_limited- 429 response, should wait for RetryInfo delay:transient- Retryable error (5xx, network):permanent- Non-retryable error (4xx except 429)
@spec execute_with_retry( (-> {:ok, term()} | {:error, term()}), Gemini.RateLimiter.State.state_key(), Gemini.RateLimiter.Config.t(), keyword() ) :: retry_result()
Execute a request function with retry handling.
Parameters
request_fn- Zero-arity function that makes the actual requeststate_key- Key for rate limit state trackingconfig- Rate limiter configurationopts- Additional options
Options
:attempt- Current attempt number (internal use)
Returns
{:ok, response}- Request succeeded{:error, {:rate_limited, retry_at, details}}- Rate limited, wait until retry_at{:error, {:transient_failure, attempts, last_error}}- Transient failure after max attempts{:error, reason}- Permanent failure
Extract retry delay from a 429 error response.