{
    "slug": "retry_pattern",
    "term": "Retry Pattern with Exponential Backoff",
    "category": "architecture",
    "difficulty": "intermediate",
    "short": "Automatically retrying failed operations with increasing delays — preventing thundering herd and handling transient failures gracefully.",
    "long": "Transient failures (network blips, rate limit 429s, database deadlocks) are often self-resolving. The Retry pattern retries the operation automatically, but naive immediate retries can overwhelm a struggling service. Exponential backoff doubles the wait on each attempt (1s, 2s, 4s, 8s...); jitter adds randomness to spread retries from many clients (prevents thundering herd). Best practices: cap maximum retries (3–5), cap maximum delay (30–60s), only retry idempotent operations (GET, PUT — not POST without idempotency keys), use a circuit breaker to stop retrying when the service is clearly down. Guzzle's retry middleware and symfony/http-client both support retry configuration. Log every retry with the delay and reason.",
    "aliases": [
        "retry logic",
        "exponential backoff",
        "retry with backoff"
    ],
    "tags": [
        "architecture",
        "resilience",
        "design-pattern"
    ],
    "misconception": "Retrying immediately after a failure is as effective as backoff. Immediate retries hammer a struggling dependency and worsen cascading failures. Exponential backoff with jitter spreads retry load, and idempotency checks ensure retried operations do not create duplicate side effects.",
    "why_it_matters": "Retrying transient failures (network blips, rate limits, temporary outages) automatically improves resilience — but retrying without backoff and jitter amplifies load on an already struggling service.",
    "common_mistakes": [
        "Retrying non-idempotent operations without checking — retrying a payment charge double-charges the customer.",
        "Constant retry interval without exponential backoff — hammers a recovering service at full rate.",
        "No jitter — all clients retry at the same time, creating a thundering herd.",
        "No maximum retry limit — infinite retries hold resources and can cause cascading failures."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "circuit_breaker",
        "idempotency",
        "bulkhead_pattern",
        "async_processing"
    ],
    "prerequisites": [
        "circuit_breaker",
        "backpressure",
        "at_least_once_delivery"
    ],
    "refs": [
        "https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/"
    ],
    "bad_code": "// Retry without backoff or limit — thundering herd:\nfor ($i = 0; $i < 10; $i++) {\n    try {\n        return $this->http->post('/payments', $data);\n    } catch (Exception $e) {\n        sleep(1); // Same interval every time — all clients retry simultaneously\n    }\n}\n// Fix: sleep(2 ** $i + random_int(0, 1000) / 1000) — exponential backoff with jitter",
    "good_code": "// Guzzle retry middleware\n$handler = HandlerStack::create();\n$handler->push(Middleware::retry(\n    fn($retries, $req, $res) => $retries < 3 && ($res?->getStatusCode() === 429),\n    fn($retries) => (int)(1000 * 2 ** $retries) // exponential ms delay\n));",
    "quick_fix": "Use exponential backoff with jitter for retries — not fixed delay, not infinite retries; always set a maximum retry count and a dead-letter destination",
    "severity": "medium",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-04-19",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/retry_pattern",
        "html_url": "https://codeclaritylab.com/glossary/retry_pattern",
        "json_url": "https://codeclaritylab.com/glossary/retry_pattern.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Retry Pattern with Exponential Backoff](https://codeclaritylab.com/glossary/retry_pattern) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/retry_pattern"
            }
        }
    }
}