Shared exponential backoff with optional full jitter.
Used by Consumer.RetryScheduler, Transport.RabbitMQ, Transport.Kafka,
Transport.NATS, and Transport.RedisStreams for reconnect delays.
Algorithm
Full jitter (default, recommended for distributed systems):
delay = random_between(0, min(cap, base * 2^attempt))Decorrelated jitter (alternative — avoids thundering herd even better):
delay = random_between(base, min(cap, last_delay * 3))No jitter (deterministic — useful in tests):
delay = min(cap, base * 2^attempt)Usage
iex> PhoenixMicro.Utils.Backoff.next_delay(3, base: 500, cap: 30_000)
# returns something between 0 and 4000ms (full jitter)
iex> PhoenixMicro.Utils.Backoff.sequence(5, base: 100, cap: 5_000, jitter: false)
[100, 200, 400, 800, 1600]
Summary
Functions
Returns the next backoff delay in milliseconds for the given attempt number.
Returns a list of count delay values — useful for testing retry sequences.
Sleeps for the calculated backoff delay. Returns the delay used (useful for logging).
Types
@type opts() :: [ base: pos_integer(), cap: pos_integer(), jitter: boolean() | :decorrelated, multiplier: number() ]
Functions
@spec next_delay(pos_integer(), opts()) :: non_neg_integer()
Returns the next backoff delay in milliseconds for the given attempt number.
attempt is 1-indexed (first retry = 1).
Options
:base— base delay in ms (default: 500):cap— maximum delay in ms (default: 30_000):jitter—truefor full jitter,falsefor none (default:true):multiplier— exponential factor (default: 2)
@spec sequence(non_neg_integer(), opts()) :: [non_neg_integer()]
Returns a list of count delay values — useful for testing retry sequences.
Example
iex> PhoenixMicro.Utils.Backoff.sequence(4, base: 100, cap: 1_000, jitter: false)
[100, 200, 400, 800]
@spec sleep(pos_integer(), opts()) :: non_neg_integer()
Sleeps for the calculated backoff delay. Returns the delay used (useful for logging).