Skip to content

Instantly share code, notes, and snippets.

@shortthirdman
Created March 25, 2025 11:43
Show Gist options
  • Save shortthirdman/ab07276bd5cef9ae43130429e733ce2d to your computer and use it in GitHub Desktop.
Save shortthirdman/ab07276bd5cef9ae43130429e733ce2d to your computer and use it in GitHub Desktop.
Async Retry Decorator
import functools
import time
import random
import asyncio
def async_retry(max_retries=3, start_delay=2, backoff_factor=2, exceptions=(Exception,)):
"""Retry decorator for async functions with exponential backoff."""
def decorator(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
delay = start_delay
last_exception = None
for attempt in range(1, max_retries + 1):
try:
return await func(*args, **kwargs)
except exceptions as e:
last_exception = e
# Add jitter to delay to prevent thundering herd problem
jitter = random.uniform(0.8, 1.2)
sleep_time = delay * jitter
print(f"Attempt {attempt} failed: {e}. Retrying in {sleep_time:.2f}s")
await asyncio.sleep(sleep_time)
# Increase delay for next attempt
delay *= backoff_factor
# If we get here, all retries failed
raise last_exception
return wrapper
return decorator
# Usage
@async_retry(max_retries=5, exceptions=(aiohttp.ClientError, asyncio.TimeoutError))
async def fetch_url(session, url):
async with session.get(url, timeout=30) as response:
return await response.text()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment