View Source partisan_retry (partisan v5.0.0-rc.16)

Overview

This module implements a structured retry mechanism with optional exponential backoff and deadline tracking, designed for reliable asynchronous retries. It wraps the Backoff library.

Key Features

  • Supports a fixed retry interval or exponential backoff.
  • Tracks retry attempts (count) and enforces a maximum retry limit.
  • Optional global deadline (in milliseconds) for all retries.
  • Integrates with erlang:start_timer/3 to fire retries after delay.

Record Structure

  • #partisan_retry{} contains retry state, including:
  • id : Identifier associated with the retry (e.g., message ID).
  • deadline : Absolute time limit in ms (from start) before giving up.
  • max_retries : Maximum allowed retry attempts.
  • interval : Default interval between retries (in ms).
  • count : Current number of failed attempts.
  • backoff : Optional backoff state (using external backoff module).
  • start_ts : Start timestamp (used for deadline tracking).

Retry Configuration Options (init/2)

Can be supplied as a proplist or map:

  • {deadline, Milliseconds} - Absolute time limit for all retries.
  • {max_retries, Count} - Max number of retry attempts.
  • {interval, Milliseconds} - Retry interval without backoff.
  • {backoff_enabled, true | false} - Enables exponential backoff.

  • {backoff_min, Milliseconds} - Minimum backoff duration.
  • {backoff_max, Milliseconds} - Maximum backoff duration.
  • {backoff_type, jitter | normal} - Type of backoff strategy.

Usage Example

{Delay, Retry1} = partisan_retry:fail(Retry0),
Ref = partisan_retry:fire(Retry1).

Return Semantics

Functions like get/1 and fail/1 return either the next delay (in ms) or an atom indicating termination conditions: max_retries or deadline.

Integration Notes

  • Caller is responsible for invoking fail/1 or succeed/1 after outcome.
  • The retry timer must be externally scheduled using fire/1 and monitored.

Summary

Functions

Returns the number of failed retry attempts so far.

Increments the retry counter and computes the next delay.

Starts a timer based on the current retry delay.

Returns the delay (in milliseconds) before the next retry should occur.

Initializes a new retry state with the given ID and options.

Resets the retry counter and (if applicable) resets the backoff state.

Types

opt()

-type opt() ::
          {deadline, non_neg_integer()} |
          {max_retries, non_neg_integer()} |
          {interval, pos_integer()} |
          {backoff_enabled, boolean()} |
          {backoff_min, pos_integer()} |
          {backoff_max, pos_integer()} |
          {backoff_type, jitter | normal}.

optional(T)

-type optional(T) :: T | undefined.

opts()

-type opts() :: [opt()] | opts_map().

opts_map()

-type opts_map() ::
          #{deadline => non_neg_integer(),
            max_retries => non_neg_integer(),
            interval => pos_integer(),
            backoff_enabled => boolean(),
            backoff_min => pos_integer(),
            backoff_max => pos_integer(),
            backoff_type => jitter | normal}.

t()

-type t() ::
          #partisan_retry{id :: any(),
                          deadline :: non_neg_integer(),
                          max_retries :: non_neg_integer(),
                          interval :: pos_integer(),
                          count :: non_neg_integer(),
                          backoff :: optional(backoff:backoff()),
                          start_ts :: optional(pos_integer())}.

Functions

count(State)

-spec count(State :: t()) -> non_neg_integer().

Returns the number of failed retry attempts so far.

fail(State)

-spec fail(State :: t()) ->
              {Time :: integer(), NewState :: t()} | {deadline | max_retries, NewState :: t()}.

Increments the retry counter and computes the next delay.

If max_retries is reached, returns {max_retries, State}. If a deadline is exceeded, get/1 will later return deadline.

Automatically initializes the start timestamp on first retry.

Returns the tuple {Delay, NewState}, or {max_retries | deadline, NewState}.

fire(State)

-spec fire(State :: t()) -> Ref :: reference() | no_return().

Starts a timer based on the current retry delay.

If the retry has expired (due to max retries or deadline), this function raises an error.

Returns the timer reference if successful; otherwise, throws max_retries or deadline error.

get(State)

-spec get(State :: t()) -> integer() | deadline | max_retries.

Returns the delay (in milliseconds) before the next retry should occur.

If no retries remain (max_retries) or the deadline has passed, returns max_retries or deadline respectively.

Returns integer() if retry is allowed, or deadline | max_retries atom.

init(Id, Opts)

-spec init(Id :: any(), Opts :: opts()) -> t().

Initializes a new retry state with the given ID and options.

The retry mechanism can be based on a fixed interval or use exponential backoff depending on options.

Set deadline to 0 to disable deadline tracking and rely solely on max_retries.

succeed(State)

-spec succeed(State :: t()) -> {Time :: integer(), NewState :: t()}.

Resets the retry counter and (if applicable) resets the backoff state.

Used after a successful attempt to stop retrying.

Returns the tuple of {Delay, NewState} where delay is the base interval or backoff.