Retry classification and scheduling utilities.
Provides functions for determining retry strategy based on Plaid error types and implementing backoff algorithms.
Used internally by PlaidEx.HTTP.Client but exposed for advanced
use cases where you need to apply retry logic outside the HTTP layer
(e.g., in background jobs or custom sync workflows).
Full jitter backoff
PlaidEx uses full jitter backoff as recommended by AWS architecture blogs for distributed systems. This is the optimal strategy for preventing thundering herds when many clients retry simultaneously.
delay = random_uniform(min(base * 2^attempt, cap))
Advantages over equal jitter or exponential backoff alone:
- Eliminates synchronized retries under load
- Reduces total attempted load by ~50% vs. no jitter
- Faster recovery from transient failures (some clients retry immediately)
Summary
Functions
Calculates the delay for a retry attempt using full jitter.
Classifies an error into a retry strategy.
Returns a human-readable description of a retry strategy.
Calculates a longer backoff delay suitable for rate limits.
Returns true if the attempt number is within the allowed max.
Types
Functions
@spec backoff_delay(pos_integer(), pos_integer(), pos_integer()) :: non_neg_integer()
Calculates the delay for a retry attempt using full jitter.
Parameters
attempt— current attempt number (1-indexed)base_ms— base delay in millisecondsmax_ms— maximum delay cap in milliseconds
Examples
iex> delay = PlaidEx.Reliability.Retry.backoff_delay(1, 500, 30_000)
iex> delay >= 0 and delay <= 500
true
iex> delay = PlaidEx.Reliability.Retry.backoff_delay(5, 500, 30_000)
iex> delay >= 0 and delay <= 8_000
true
@spec classify(PlaidEx.Error.t()) :: :no_retry | :with_backoff | :with_long_backoff | :reauthenticate
Classifies an error into a retry strategy.
Returns the recommended strategy for the given error:
:no_retry— do not retry (user error, invalid request):immediate— retry immediately (rare, only for very transient errors):with_backoff— retry with exponential backoff (most retryable errors):with_long_backoff— retry with longer delays (rate limits, maintenance):reauthenticate— do not retry; user must re-authenticate
@spec describe(retry_strategy()) :: String.t()
Returns a human-readable description of a retry strategy.
@spec rate_limit_delay(pos_integer()) :: pos_integer()
Calculates a longer backoff delay suitable for rate limits.
Uses base of 5 seconds with a cap of 5 minutes.
@spec should_retry?(pos_integer(), non_neg_integer()) :: boolean()
Returns true if the attempt number is within the allowed max.