retry logic

Retry Logic with Exponential Backoff is the resilience pattern that automatically re-attempts failed API requests with progressively increasing wait times — the fundamental strategy for handling transient failures in AI API integrations where rate limits (429), server errors (500-503), and network timeouts are common and expected failure modes requiring graceful recovery rather than immediate hard failure.

What Is Retry Logic with Exponential Backoff?

  • Definition: A retry strategy where failed requests are automatically re-attempted after a waiting period that doubles with each successive failure — starting short (1 second) and growing exponentially (2s, 4s, 8s, 16s) to reduce load on the recovering service while giving it time to stabilize.
  • Problem Solved: AI APIs (OpenAI, Anthropic, Google) regularly return transient errors — rate limit exceeded, server overloaded, network timeout — that resolve themselves within seconds. Without retry logic, these transient failures cause application-visible errors that could have been silently recovered.
  • Jitter: Random noise added to backoff wait times — prevents the "Thundering Herd" problem where all clients that failed simultaneously retry at exactly the same moment, creating a retry spike that overwhelms the recovering server again.
  • Max Retries: Retry logic must have a ceiling — infinite retries create applications that hang indefinitely on non-transient failures. Typical: 3-5 retries with exponential backoff.

Why Retry Logic Matters for AI APIs

  • Rate Limits Are Expected: OpenAI, Anthropic, and Google enforce per-minute and per-day token and request rate limits. Applications approaching limits regularly receive 429 responses — retry with backoff is the designed response.
  • Server Load Variability: AI inference is computationally expensive — API providers experience load spikes where 503 responses signal temporary capacity constraints that resolve in seconds.
  • Network Reliability: Long-running LLM inference requests (10-60 seconds for large generations) are vulnerable to network timeouts, connection resets, and proxy failures.
  • Production SLA Requirements: User-facing AI applications cannot display API error messages to end users — transparent retry logic maintains application availability during transient failures.
  • Cost Efficiency: Retrying transient failures is dramatically cheaper than adding error handling paths, fallback systems, or manual re-submission workflows.

Exponential Backoff Algorithm

Core algorithm:

wait_time = base_delay × (2 ^ retry_count) + random_jitter

Retry 1: 1 × 2^0 + jitter = 1.0 ± 0.5 seconds
Retry 2: 1 × 2^1 + jitter = 2.0 ± 0.5 seconds
Retry 3: 1 × 2^2 + jitter = 4.0 ± 0.5 seconds
Retry 4: 1 × 2^3 + jitter = 8.0 ± 0.5 seconds
Retry 5: 1 × 2^4 + jitter = 16.0 ± 0.5 seconds (then give up)

Which Errors to Retry

HTTP StatusError TypeRetry?Reason
429Rate limit exceededYesWait and retry
500Internal server errorYes (limited)May be transient
502Bad gatewayYesInfrastructure issue
503Service unavailableYesServer overloaded
504Gateway timeoutYesTimeout — retry may succeed
400Bad requestNoRequest is malformed — retry won't help
401UnauthorizedNoWrong API key — retry won't help
403ForbiddenNoPermission issue — retry won't help
404Not foundNoWrong endpoint — retry won't help

Implementation Examples

Python with tenacity library (Recommended):

from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
import openai

@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=1, max=60),
    retry=retry_if_exception_type((openai.RateLimitError, openai.APIStatusError))
)
def call_llm(prompt: str) -> str:
    return client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}]
    ).choices[0].message.content

Manual Implementation with Jitter:

import time, random

def call_with_backoff(prompt: str, max_retries: int = 5) -> str:
    for attempt in range(max_retries):
        try:
            return llm.generate(prompt)
        except (RateLimitError, ServerError) as e:
            if attempt == max_retries - 1:
                raise  # Last attempt — propagate error
            wait = (2 ** attempt) + random.uniform(0, 1)  # Exponential + jitter
            time.sleep(wait)

Rate Limit Header Handling (Advanced):
OpenAI returns headers indicating when the rate limit resets:

except RateLimitError as e:
    reset_time = e.response.headers.get("x-ratelimit-reset-requests")
    if reset_time:
        wait = max(float(reset_time), 1.0)  # Wait until reset, not just backoff
        time.sleep(wait)

Production Considerations

  • Circuit Breaker: After N consecutive failures, stop retrying for a cooldown period — prevents cascading failures where retries amplify overload.
  • Async Retry: For high-throughput applications, use async retry to avoid blocking threads during backoff waits.
  • User Feedback: For user-facing applications with long retry queues, provide progress indication — "Processing your request..." — rather than silent delays.
  • Monitoring: Track retry rates, backoff durations, and ultimate failure rates — high retry rates indicate systematic issues requiring architectural response.
  • Budget Accounting: Retries multiply API costs — ensure retry behavior is accounted for in cost modeling.

Retry logic with exponential backoff is the foundational resilience pattern that separates brittle AI prototypes from production-grade AI applications — by automatically recovering from the transient failures that are inevitable when calling AI APIs at scale, retry logic with jitter transforms occasional API hiccups from user-visible errors into seamless, transparent recovery that maintains application reliability and user trust.

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account