import time
from functools import wraps
from typing import Callable, Type, Tuple, Optional
def retry(
max_attempts: int = 3,
delay: float = 1,
backoff: float = 2,
exceptions: Tuple[Type[Exception], ...] = (Exception,)
):
"""
Decorator to retry a function with exponential backoff.
Args:
max_attempts: Maximum number of retry attempts
delay: Initial delay in seconds
backoff: Backoff multiplier
exceptions: Tuple of exception types to catch
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
current_delay = delay
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except exceptions as e:
last_exception = e
if attempt < max_attempts - 1:
time.sleep(current_delay)
current_delay *= backoff
else:
raise
raise last_exception
return wrapper
return decorator