💻
Code Snippet — July 31, 2026Retry with Exponential Backoff, Jitter & Circuit Breaker (Python 3.10+)
Zero-dependency
@retry decorator for flaky APIs, DB connections, and network calls:
import random, time, functools
from typing import Callable, Type, Optional
def retry(max_attempts=3, base_delay=1.0, max_delay=60.0,
backoff_factor=2.0, jitter="full",
retryable_exceptions=(Exception,),
circuit_breaker=0, circuit_cooldown=30.0,
max_elapsed=None,
on_retry=None):
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.monotonic()
for attempt in range(1, max_attempts + 1):
if max_elapsed and (time.monotonic() - start >= max_elapsed):
raise TimeoutError(f"Exceeded max_elapsed={max_elapsed}s")
try:
return func(*args, **kwargs)
except retryable_exceptions as exc:
if attempt == max_attempts:
raise
delay = min(base_delay * (backoff_factor ** (attempt - 1)), max_delay)
if jitter == "full":
delay = random.uniform(0, delay)
elif jitter == "equal":
delay = random.uniform(delay / 2, delay)
if on_retry:
on_retry(attempt, delay, exc)
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=5, jitter="full", max_elapsed=30)
def call_api():
...
Features: Exponential backoff + 3 jitter modes, per-exception policies, circuit breaker, wall-clock deadline, logging hooks. Full version with circuit breaker +
per_exception map in today's workspace.
When you can't add tenacity (Lambda cold starts, Dockerfile limits), this gives you production-grade retry logic in one decorator.