Concepts/ReliabilityFoundational4 min

Retry with Exponential Backoff

Retry transient failures slowly enough that recovery is possible.

retriesbackoffreliabilityfailures

Prerequisites

What it is

Exponential backoff retries failed work after increasing delays, often with jitter to avoid synchronized retry storms.

Why it matters

Many failures are temporary. Retrying immediately can overload the recovering dependency and make the incident worse. Backoff gives systems breathing room.

How it works

After each failure, wait longer before trying again: 1 second, 2 seconds, 4 seconds, 8 seconds, up to a cap. Jitter adds randomness to spread retries out.

# config: base=1s, cap=30s, max_attempts=5

function call_with_retry(operation):
    for attempt in 1..max_attempts:
        try:
            return operation()
        except transient_error:
            if attempt == max_attempts:
                raise                # give up, move to DLQ

            delay = min(cap, base * 2^(attempt - 1))
            jitter = random(0, delay / 2)   # "full jitter"
            sleep(delay + jitter)

Without jitter, many clients retry at the exact same intervals, creating synchronized spikes. Jitter spreads them out so the recovering system sees a smooth ramp instead of a thundering herd.

When to use it

Use it for network calls, webhooks, queues, uploads, payment provider calls, and eventually consistent background work.

Tradeoffs / failure modes

Retries require idempotency. Too many retries waste capacity; too few reduce reliability. Permanent errors should not be retried.

Tiny example

A webhook delivery fails with 503, then retries after 2s, 5s, 12s, and 30s before moving to a dead-letter queue.

See Webhooks, Job Queues, Payment Processing, File Upload Pipeline, GitHub, Gmail, and Slack.

Seen in deeper dives

Related concepts