Retry logic with configurable backoff strategies.
Strategies
:exponential- Exponential backoff (default):linear- Linear backoff:constant- Fixed delayfun/1- Custom backoff function
Options
:max_attempts- Maximum retry attempts (default: 4):base_delay_ms- Base delay for backoff (default: 200):max_delay_ms- Maximum delay cap (default: 10_000):jitter- Add random jitter (default: true):retry_if- Predicate to determine if error is retryable:on_retry- Callback invoked on each retry
Example
Codex.Retry.with_retry(fn ->
make_api_call()
end, max_attempts: 3, strategy: :exponential)
Summary
Functions
Calculates delay for given attempt using configured strategy.
Returns the default options for retry operations.
Default predicate for retryable errors.
Executes function with retry logic.
Wraps an async stream with retry logic.
Types
@type opts() :: [ max_attempts: pos_integer(), base_delay_ms: non_neg_integer(), max_delay_ms: non_neg_integer(), jitter: boolean(), strategy: strategy(), retry_if: (term() -> boolean()), on_retry: (attempt :: pos_integer(), error :: term() -> :ok) ]
@type strategy() :: :exponential | :linear | :constant | (attempt :: pos_integer() -> non_neg_integer())
Functions
@spec calculate_delay(pos_integer(), opts()) :: non_neg_integer()
Calculates delay for given attempt using configured strategy.
Examples
iex> opts = [base_delay_ms: 100, max_delay_ms: 10_000, strategy: :exponential, jitter: false]
iex> Codex.Retry.calculate_delay(1, opts)
100
iex> Codex.Retry.calculate_delay(2, opts)
200
iex> Codex.Retry.calculate_delay(3, opts)
400
@spec default_opts() :: opts()
Returns the default options for retry operations.
Useful for inspecting or modifying default configuration.
Examples
iex> Codex.Retry.default_opts()[:max_attempts]
4
Default predicate for retryable errors.
Retries on:
- Timeout errors
- Connection errors
- 5xx HTTP errors
- Rate limit errors (429)
Codex.Errorwith:rate_limitkind- Stream errors
Codex.TransportErrorwithretryable?: true
Does NOT retry on:
- Authentication errors
- Invalid request errors
- Context window exceeded
- Unknown error types
Examples
iex> Codex.Retry.retryable?(:timeout)
true
iex> Codex.Retry.retryable?({:http_error, 503})
true
iex> Codex.Retry.retryable?({:http_error, 429})
true
iex> Codex.Retry.retryable?({:http_error, 401})
false
iex> Codex.Retry.retryable?(:auth_failed)
false
Executes function with retry logic.
Returns {:ok, result} on success or {:error, reason} after all attempts exhausted.
Options
:max_attempts- Maximum number of attempts (default: 4):base_delay_ms- Base delay in milliseconds (default: 200):max_delay_ms- Maximum delay cap in milliseconds (default: 10_000):jitter- Add random jitter to delays (default: true):strategy- Backoff strategy (default::exponential):retry_if- Predicate function to determine if error is retryable:on_retry- Callback invoked before each retry with attempt number and error
Examples
# Basic usage with defaults
Codex.Retry.with_retry(fn -> make_api_call() end)
# Custom configuration
Codex.Retry.with_retry(
fn -> risky_operation() end,
max_attempts: 5,
base_delay_ms: 100,
strategy: :linear,
on_retry: fn attempt, error ->
Logger.warning("Retry #{attempt}: #{inspect(error)}")
end
)
@spec with_stream_retry((-> Enumerable.t()), opts()) :: Enumerable.t()
Wraps an async stream with retry logic.
For streaming operations, retries the entire stream from the beginning when a retryable error occurs.
Options
Same as with_retry/2.
Examples
stream = Codex.Retry.with_stream_retry(fn ->
make_streaming_request()
end, max_attempts: 3)
Enum.each(stream, &process_item/1)