retry_with_backoff decorator with jitter
Python
"""Retry a callable with capped exponential backoff and full jitter."""
import functools
import random
import time
from typing import Callable, TypeVar
T = TypeVar("T")
def retry_with_backoff(
attempts: int = 4,
base_delay: float = 0.1,
max_delay: float = 5.0,
retry_on: tuple[type[BaseException], ...] = (OSError,),
) -> Callable[[Callable[..., T]], Callable[..., T]]:
"""Decorate a callable: failed attempts sleep, then retry."""
def decorate(func: Callable[..., T]) -> Callable[..., T]:
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(1, attempts + 1):
try:
return func(*args, **kwargs)
except retry_on:
if attempt == attempts:
raise
ceiling = min(max_delay, base_delay * 2 ** (attempt - 1))
time.sleep(random.uniform(0, ceiling)) # full jitter
raise RuntimeError("retry loop exhausted")
return wrapper
return decorate