LemonCore.Retry (lemon_core v0.1.0)

View Source

Shared retry backoff utilities extracted from duplicated implementations across lemon_channels and lemon_gateway.

Summary

Functions

Exponential backoff capped at a maximum value, with optional jitter.

Exponential backoff: base_ms * 2^attempt.

Exponential backoff with a configurable multiplier (factor).

Parses a retry-after value from an HTTP response body.

Adds symmetric jitter to a delay value.

Functions

capped_backoff(base_ms, attempt, max_ms, opts \\ [])

@spec capped_backoff(pos_integer(), non_neg_integer(), pos_integer(), keyword()) ::
  pos_integer()

Exponential backoff capped at a maximum value, with optional jitter.

Options

  • :factor - growth factor (default: 2)
  • :jitter - jitter fraction, 0 to disable (default: 0)

Examples

iex> LemonCore.Retry.capped_backoff(500, 2, 10_000)
2000
iex> LemonCore.Retry.capped_backoff(500, 10, 10_000)
10_000

exponential_backoff(base_ms, attempt)

@spec exponential_backoff(pos_integer(), non_neg_integer()) :: pos_integer()

Exponential backoff: base_ms * 2^attempt.

Examples

iex> LemonCore.Retry.exponential_backoff(500, 0)
500
iex> LemonCore.Retry.exponential_backoff(500, 3)
4000

exponential_backoff(base_ms, attempt, factor)

@spec exponential_backoff(pos_integer(), non_neg_integer(), number()) :: pos_integer()

Exponential backoff with a configurable multiplier (factor).

Useful when the growth factor is not 2 (e.g. WhatsApp reconnect uses 1.8).

Examples

iex> LemonCore.Retry.exponential_backoff(2000, 0, 1.8)
2000

parse_retry_after(body)

@spec parse_retry_after(term()) :: non_neg_integer()

Parses a retry-after value from an HTTP response body.

Supports:

  • JSON body with parameters.retry_after (Telegram-style)
  • Plain text with "retry after N" pattern

Returns milliseconds, or 0 if not found.

with_jitter(delay_ms, jitter_fraction \\ 0.25)

@spec with_jitter(number(), float()) :: non_neg_integer()

Adds symmetric jitter to a delay value.

Returns a value in the range [delay * (1 - jitter_fraction), delay * (1 + jitter_fraction)].

Examples

iex> result = LemonCore.Retry.with_jitter(1000, 0.25)
iex> result >= 750 and result <= 1250
true