← Back to Blog
Code Snippets July 10, 2026

Code Snippet — July 10, 2026 ### Async Retry with Exponential Backoff, Ji

🐍 Code Snippet — July 10, 2026

Async Retry with Exponential Backoff, Jitter & Circuit Breaker



A production-grade @retry decorator for async def — zero dependencies:

import asyncio, functools, random
_budget, _circuit = {}, {}

def retry(max_attempts=3, backoff_base=1.0, backoff_max=30.0,
          jitter='random', circuit_breaker=None, budget=None,
          retry_on=Exception, on_retry=None):
    def decorator(func):
        key = f'{func.__module__}.{func.__qualname__}'
        @functools.wraps(func)
        async def wrapper(*a, **kw):
            for attempt in range(1, max_attempts+1):
                try:
                    r = await func(*a, **kw)
                    if circuit_breaker: _circuit[key]=0
                    if budget: _budget[key]=budget
                    return r
                except Exception as e:
                    if not isinstance(e, retry_on): raise
                    if attempt >= max_attempts: raise
                    if circuit_breaker:
                        _circuit[key] = _circuit.get(key,0)+1
                        if _circuit[key]>=circuit_breaker:
                            raise RuntimeError('Open') from e
                    if budget:
                        if _budget.get(key,0)<=0: raise RuntimeError('Exhausted') from e
                        _budget[key] -= 1
                    d = min(backoff_base*2**(attempt-1), backoff_max)
                    if jitter=='random': d=random.uniform(0,d)
                    elif jitter=='full': d=random.uniform(0,backoff_max)
                    if on_retry: on_retry(attempt,d,e)
                    await asyncio.sleep(d)
            raise e
        return wrapper
    return decorator


💡 jitter='full' prevents thundering herds. budget=50 caps retries. circuit_breaker=10 stops after consecutive failures. Replaces bare try/except + time.sleep() — the #1 async anti-pattern.