# Created on savesnippets.com ยท https://savesnippets.com/PJU4ioaRcHdmrc import asyncio import random from typing import Awaitable, Callable, TypeVar T = TypeVar("T") async def aretry( fn: Callable[[], Awaitable[T]], attempts: int = 5, base: float = 0.2, should_retry: Callable[[BaseException], bool] = lambda _: True, ) -> T: last: BaseException | None = None for i in range(1, attempts + 1): try: return await fn() except BaseException as e: last = e if i == attempts or not should_retry(e): raise delay = base * (2 ** (i - 1)) await asyncio.sleep(delay + random.random() * delay) raise RuntimeError("unreachable") from last async def flaky(): if random.random() < 0.8: raise ConnectionError("oops") return "ok" print(asyncio.run(aretry(flaky, attempts=10)))