Reliability engineering

Retry with exponential backoff and jitter without creating a retry storm

Retries improve reliability only when the failed operation is safe to repeat and the client knows when to stop. A loop that retries every error on the same schedule can amplify an outage instead of recovering from it.

By Moresq Corpus10 min read
A catalogue of implementation cards passing through a quality gate into a repository with a receipt.
A retry helper is reusable only when the surrounding policy—eligible errors, budget, jitter and cancellation—is explicit. Open image.

How to design retries with exponential backoff, jitter, retry budgets, cancellation, idempotency and tests for JavaScript, TypeScript and Python services.

Decide whether the operation is retryable before calculating a delay

The first question is not how long to sleep. It is whether the operation can be repeated without creating another side effect. Reads are often safe. Writes may require an idempotency key, a conditional update or a transaction-specific recovery path.

Retry transient failures such as selected timeouts, connection resets, rate limits and explicit service-unavailable responses. Do not automatically retry authentication failures, malformed input, permission errors or deterministic business-rule failures.

When the server returns Retry-After, respect it within the client’s overall deadline. The server has more information about its recovery window than a generic client formula.

Backoff limits request pressure; jitter prevents synchronization

Exponential backoff grows the delay after each failed attempt. A cap prevents the delay from becoming impractical. Jitter randomizes the selected delay so thousands of clients do not wake at the same boundary and hit the recovering service together.

Full jitter chooses a random value between zero and the capped exponential delay. Equal or decorrelated jitter can reduce variance for other workloads. The important property is that clients do not share one deterministic schedule.

Delay model, not a complete retry policytext
ceiling = min(max_delay, base_delay * 2 ** attempt)
delay = random_between(0, ceiling)
sleep(delay)

Use a retry budget, not only a maximum attempt count

Attempt limits are easy to understand but incomplete. Three attempts can take milliseconds for one service and thirty seconds for another. Track both maximum attempts and maximum elapsed time, then stop when either boundary is reached.

Propagate cancellation from the caller. A user navigation, deployment shutdown or expired request should interrupt sleep and in-flight work. Background retries that outlive their owner consume capacity and make incidents harder to diagnose.

  • Maximum attempts.
  • Maximum total elapsed time.
  • Per-attempt timeout.
  • Backoff cap.
  • Caller cancellation signal.
  • Operation idempotency state.
  • Allowed error and status classes.

Log the reason and budget without leaking credentials

A retry metric should distinguish first-attempt success from eventual success. Record the operation name, attempt number, error class, selected delay and final outcome. Redact authorization headers, tokens and request bodies.

High retry volume can be an early incident signal. Track retry rate, exhausted budgets and added latency by dependency. If most requests succeed only after retries, the service is not healthy simply because the user eventually received a response.

Test time deterministically

Inject the clock, random source and sleep function so the test suite does not wait in real time. Verify the range of jittered delays, cap behavior, retry eligibility and cancellation. A deterministic random sequence makes edge cases reproducible.

For side-effecting operations, test the idempotency behavior at the integration boundary. The retry utility can schedule another attempt; only the operation and its storage contract can prove that a repeated request is harmless.

  • Non-retryable errors fail immediately.
  • Transient errors stop after the attempt or elapsed-time budget.
  • Jitter remains inside the expected range.
  • Delay never exceeds the configured cap.
  • Cancellation interrupts waiting and work.
  • Retry-After is respected within the caller deadline.
  • Idempotency prevents repeated side effects.

FAQ

Frequently asked questions

What is jitter in a retry strategy?

Jitter randomizes retry delays so clients do not synchronize and overwhelm a recovering dependency at the same time.

Which errors should be retried?

Retry only errors classified as transient and only when the operation is safe to repeat. Authentication, validation and deterministic business errors should normally fail immediately.

How many retry attempts should I use?

There is no universal number. Combine an attempt limit with a maximum elapsed-time budget and the caller’s deadline.

Does exponential backoff make a write safe to retry?

No. Safety comes from the operation’s idempotency or transaction design. Backoff only changes request timing.

Moresq Corpus

Retrieve proven code with source, rights and proof attached.