ExternalService.RetryOptions (ExternalService v2.5.0)

Copy Markdown View Source

Options that control retry logic for calls to external services.

Retry options can be given either as this struct or as a plain keyword list (which is validated and converted with new/1). The available options are:

  • :backoff - The backoff strategy used to grow the delay between retries. The default value is :exponential.

  • :base (non_neg_integer/0) - The initial delay between retries, in milliseconds (0 for no delay). The default value is 10.

  • :factor (pos_integer/0) - Growth factor applied on each retry. Only used for :linear backoff. The default value is 1.

  • :cap (pos_integer/0) - Caps the delay between retries to at most this many milliseconds.

  • :expiry - Total time budget for retries, in milliseconds. Retrying stops once exceeded. Defaults to no time budget; :infinity states that explicitly (see the note on unbounded retries below).

  • :max_attempts - Maximum number of attempts (the initial attempt plus retries). Defaults to no limit; :infinity states that explicitly (see the note on unbounded retries below).

  • :jitter - Random jitter applied to delays. true applies +/- 10%; a float (e.g. 0.25) applies that proportion. Helps avoid retrying in lockstep (thundering herd). The default value is false.

  • :retry_on (function of arity 1) - A predicate run on the return value of the call. When it returns a truthy value the call is retried, exactly as if the function had returned :retry (the result itself is used as the retry reason, and the circuit breaker melts). Lets you drive retries from a function that was not written to return :retry/{:retry, reason}. Defaults to no predicate. An explicit :retry/{:retry, reason} return always takes precedence over the predicate.

  • :retry_exceptions (list of atom/0) - Exception modules that should trigger a retry when raised. Defaults to [], meaning raised exceptions are not retried; use :retry/{:retry, reason} return values, or the :retry_on predicate, to drive retries instead. The default value is [].

Unbounded retries

Neither :max_attempts nor :expiry has a default, so options that set neither place no bound on retrying: a call that keeps returning :retry keeps retrying forever. The circuit breaker is not a reliable backstop for this — exponential backoff widens the gap between attempts until failures no longer accumulate fast enough to open it. Almost always, you want one of these set. See Bounding retries for the details.

ExternalService.start/2 logs a warning when a service's default retry options leave both unset. If unbounded retrying really is what you want — or every call site supplies its own bound — say so explicitly with :infinity, which behaves identically but silences the warning:

ExternalService.start(:my_service, retry: [max_attempts: :infinity])

Summary

Functions

Layers a keyword list of per-call overrides onto a base struct.

Builds a validated RetryOptions struct from a keyword list (or returns an existing struct unchanged).

Types

t()

@type t() :: %ExternalService.RetryOptions{
  backoff: :exponential | :linear,
  base: non_neg_integer(),
  cap: pos_integer() | nil,
  expiry: pos_integer() | :infinity | nil,
  factor: pos_integer(),
  jitter: boolean() | float(),
  max_attempts: pos_integer() | :infinity | nil,
  retry_exceptions: [module()],
  retry_on: (term() -> as_boolean(term())) | nil
}

Functions

merge(base, retry_options)

@spec merge(t(), t() | keyword()) :: t()

Layers a keyword list of per-call overrides onto a base struct.

Only the keys actually present in opts are overridden; every other field is taken from base. This is how per-call retry options tweak — rather than reset — a service's configured defaults. A %RetryOptions{} given in place of the keyword list replaces base wholesale, since a struct is already a complete set of options.

Raises NimbleOptions.ValidationError if opts is invalid.

new(retry_options)

@spec new(t() | keyword()) :: t()

Builds a validated RetryOptions struct from a keyword list (or returns an existing struct unchanged).

Raises NimbleOptions.ValidationError if the options are invalid.