Dowser.Client.Retry (Dowser.Client v0.1.1)

View Source

Generic retry policy for transient HTTP failures.

Lives outside Dowser.Client.HTTP.* deliberately: retry is orchestration around whichever adapter is configured, not a transport concern, so it works uniformly for :httpc, Req, :hackney and any custom adapter.

resolve/1 turns opts[:retry] into a full config (stored on %Dowser.Client.Request{}); run/2 drives an arbitrary zero-arity fun through that policy, sleeping between attempts with exponential full-jitter backoff; transient?/1 classifies an adapter's raw {:error, reason} payload.

Options

opts[:retry] accepts:

  • false — disables retries (max_attempts: 1).
  • a keyword list — merged over the defaults, so a partial override (e.g. retry: [max_attempts: 5]) only changes the given keys:
    • :max_attempts — total attempts, including the first (default 3).
    • :base_delay_ms / :max_delay_ms — exponential full-jitter backoff bounds (default 200 / 2_000).
    • :retryable_statuses — response statuses treated as transient (default [429, 502, 503, 504]).

Summary

Functions

Resolves opts[:retry] into a full retry config.

Runs fun up to config[:max_attempts] times, retrying as long as the result is transient (a retryable HTTP status or a transient transport error) and attempts remain, sleeping with jittered backoff in between.

Whether an adapter's raw {:error, reason} payload looks transient.

Types

config()

@type config() :: keyword()

Functions

resolve(opts)

@spec resolve(keyword()) :: {:ok, config()} | {:error, Dowser.Client.Error.t()}

Resolves opts[:retry] into a full retry config.

Returns {:ok, config} or {:error, %Dowser.Client.Error{}} when opts[:retry] is neither false nor a keyword list.

run(config, fun)

@spec run(config(), (-> term())) :: {term(), pos_integer()}

Runs fun up to config[:max_attempts] times, retrying as long as the result is transient (a retryable HTTP status or a transient transport error) and attempts remain, sleeping with jittered backoff in between.

Returns {result, attempts}fun's final return value and the number of times it was actually called.

transient?(reason)

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

Whether an adapter's raw {:error, reason} payload looks transient.