← Back to Blog
Code Snippets July 5, 2026

Async Retry with Exponential Backoff, Jitter & Circuit Breaker

🐍 Code Snippet — July 5, 2026

Async Retry with Exponential Backoff, Jitter & Circuit Breaker

A production-ready @async_retry decorator for any async def function.

What it gives you:
  • Exponential backoff (1s → 2s → 4s → 8s...)

  • Randomized jitter ±25% (prevents thundering herds)

  • Exception filtering (retry ConnectionError, let ValueError propagate)

  • Circuit breaker (stops retrying after N consecutive failures)

  • Metrics callback for Prometheus/Datadog


The Code:
```python
import asyncio, functools, random, time, logging
from typing import Callable, Optional

logger = logging.getLogger(__name__)

def async_retry(
max_attempts: int = 3,
base_delay: float = 1.0,
max_delay: float = 60.0,
jitter: bool = True,
retry_on=Exception,
on_retry: Optional[Callable] = None,
) -> Callable:
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
async def wrapper(*args, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return await func(*args, **kwargs)
except retry_on as exc:
if attempt == max_attempts:
raise
delay = min(base_delay * (2 ** (attempt - 1)), max_delay)
if jitter:
delay += random.uniform(-delay 0.25, delay 0.25)
delay = max(0.1, delay)
if on_retry:
on_retry(attempt, delay, exc)
await asyncio.sleep(delay)
except Exception:
raise
raise
return wrapper
return decorator

Usage:


@async_retry(
max_attempts=5,
base_delay=1.0,
retry_on=(ConnectionError, TimeoutError),
... (continued in thread)