WeaviateEx.Protocol.HTTP.Retry (WeaviateEx v0.7.4)

View Source

HTTP transport-level retry with exponential backoff and jitter.

Mirrors gRPC retry behavior for HTTP operations. Retries on:

Transport Errors

  • Connection refused (:econnrefused)
  • Connection reset (:econnreset)
  • Timeout (:timeout)
  • Connection closed (:closed)
  • DNS resolution failed (:nxdomain)

HTTP Status Codes

  • 408 Request Timeout
  • 429 Too Many Requests (rate limit)
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout

Usage

alias WeaviateEx.Protocol.HTTP.Retry

result = Retry.with_retry(fn ->
  Finch.request(request, WeaviateEx.Finch, receive_timeout: timeout)
end)

Options

  • :max_retries - Maximum number of retry attempts (default: 3)
  • :base_delay_ms - Base delay in milliseconds for backoff calculation (default: 100)
  • :max_delay_ms - Maximum delay cap in milliseconds (default: 5000)

Backoff Strategy

Uses exponential backoff with jitter: min(2^attempt * base_delay_ms, max_delay_ms) plus random jitter of ±10%.

Attempt 0: ~100ms (with jitter) Attempt 1: ~200ms (with jitter) Attempt 2: ~400ms (with jitter) Attempt 3: ~800ms (with jitter) ...capped at max_delay_ms

Summary

Functions

Calculate exponential backoff delay with jitter for a given attempt number.

Returns the default retry options.

Check if an HTTP status code is retryable.

Returns the list of retryable HTTP status codes.

Check if an error is a retryable transport error.

Execute a function with automatic retry on transient errors.

Types

retry_opts()

@type retry_opts() :: [
  max_retries: non_neg_integer(),
  base_delay_ms: non_neg_integer(),
  max_delay_ms: non_neg_integer()
]

Functions

calculate_backoff(attempt)

@spec calculate_backoff(non_neg_integer()) :: non_neg_integer()

Calculate exponential backoff delay with jitter for a given attempt number.

Returns delay in milliseconds with ±10% jitter, capped at max_delay_ms.

Examples

Retry.calculate_backoff(0)  # => ~100ms (with jitter)
Retry.calculate_backoff(1)  # => ~200ms (with jitter)
Retry.calculate_backoff(2)  # => ~400ms (with jitter)
Retry.calculate_backoff(10) # => ~5000ms (capped at max_delay_ms)

default_retry_opts()

@spec default_retry_opts() :: retry_opts()

Returns the default retry options.

Examples

Retry.default_retry_opts()
# => [max_retries: 3, base_delay_ms: 100, max_delay_ms: 5000]

retryable_status_code?(status)

@spec retryable_status_code?(integer()) :: boolean()

Check if an HTTP status code is retryable.

Retryable status codes: 408, 429, 500, 502, 503, 504

Examples

Retry.retryable_status_code?(503)  # => true
Retry.retryable_status_code?(429)  # => true
Retry.retryable_status_code?(400)  # => false
Retry.retryable_status_code?(404)  # => false

retryable_status_codes()

@spec retryable_status_codes() :: [integer()]

Returns the list of retryable HTTP status codes.

Examples

Retry.retryable_status_codes()
# => [408, 429, 500, 502, 503, 504]

retryable_transport_error?(arg1)

@spec retryable_transport_error?(term()) :: boolean()

Check if an error is a retryable transport error.

Returns true for transient transport errors that are safe to retry:

  • Connection refused
  • Connection reset
  • Timeout
  • Connection closed
  • DNS resolution failed

Examples

Retry.retryable_transport_error?(%Mint.TransportError{reason: :econnrefused})  # => true
Retry.retryable_transport_error?(%Mint.TransportError{reason: :invalid_cert})  # => false
Retry.retryable_transport_error?({:error, %Mint.TransportError{reason: :timeout}})  # => true

with_retry(fun, opts \\ [])

@spec with_retry((-> result), retry_opts()) :: result when result: any()

Execute a function with automatic retry on transient errors.

Retries on transport errors (connection refused, timeout, etc.) and retryable HTTP status codes (429, 500, 502, 503, 504, 408).

Options

  • :max_retries - Maximum retry attempts (default: 3)
  • :base_delay_ms - Base delay for exponential backoff (default: 100)
  • :max_delay_ms - Maximum delay cap (default: 5000)

Examples

Retry.with_retry(fn ->
  Finch.request(request, WeaviateEx.Finch, receive_timeout: 30_000)
end)

Retry.with_retry(
  fn -> Finch.request(request, WeaviateEx.Finch, receive_timeout: 30_000) end,
  max_retries: 5,
  base_delay_ms: 200,
  max_delay_ms: 10_000
)