Durable.Executor.Backoff (Durable v0.1.0-rc)

View Source

Backoff strategies for step retry logic.

Supports three backoff strategies:

  • :exponential - Delay grows exponentially (2^attempt * base)
  • :linear - Delay grows linearly (attempt * base)
  • :constant - Fixed delay between retries

All delays are in milliseconds and capped at a configurable maximum.

Summary

Functions

Calculates the delay before the next retry attempt.

Calculates delay with jitter to avoid thundering herd.

Sleeps for the calculated backoff duration.

Types

opts()

@type opts() :: %{
  optional(:base) => pos_integer(),
  optional(:max_backoff) => pos_integer()
}

strategy()

@type strategy() :: :exponential | :linear | :constant

Functions

calculate(strategy, attempt, opts \\ %{})

@spec calculate(strategy(), pos_integer(), opts()) :: pos_integer()

Calculates the delay before the next retry attempt.

Arguments

  • strategy - The backoff strategy to use
  • attempt - The current attempt number (1-based)
  • opts - Options for the backoff calculation

Options

  • :base - Base delay in milliseconds (default: 1000)
  • :max_backoff - Maximum delay in milliseconds (default: 30000 = 30s). Kept low because the backoff blocks the worker in-process; raise it only if your stale_lock_timeout comfortably exceeds the chosen ceiling.

Examples

iex> Backoff.calculate(:exponential, 1, %{base: 1000})
2000

iex> Backoff.calculate(:exponential, 3, %{base: 1000})
8000

iex> Backoff.calculate(:linear, 3, %{base: 1000})
3000

iex> Backoff.calculate(:constant, 5, %{base: 1000})
1000

calculate_with_jitter(strategy, attempt, opts \\ %{})

@spec calculate_with_jitter(strategy(), pos_integer(), opts()) :: non_neg_integer()

Calculates delay with jitter to avoid thundering herd.

Adds random jitter of ±25% to the calculated delay.

Examples

# Delay will be between 1500 and 2500 for exponential with attempt=1
Backoff.calculate_with_jitter(:exponential, 1, %{base: 1000})

sleep(strategy, attempt, opts \\ %{})

@spec sleep(strategy(), pos_integer(), opts()) :: :ok

Sleeps for the calculated backoff duration.

Examples

Backoff.sleep(:exponential, 2, %{base: 1000})