from __future__ import annotations import asyncio import random import time class BackoffManager: def __init__( self, base_delay: float = 1.0, max_delay: float = 60.0, multiplier: float = 2.0, jitter: float = 0.1, ): self._base_delay = base_delay self._max_delay = max_delay self._multiplier = multiplier self._jitter = jitter self._attempt = 0 self._last_attempt_at: float = 0 def reset(self) -> None: self._attempt = 0 @property def attempts(self) -> int: return self._attempt def should_reconnect(self, max_attempts: int = 10) -> bool: return self._attempt < max_attempts async def wait(self) -> bool: self._attempt += 1 delay = min( self._base_delay * (self._multiplier ** (self._attempt - 1)), self._max_delay, ) jitter_amount = delay * self._jitter * random.random() actual_delay = delay + jitter_amount self._last_attempt_at = time.monotonic() await asyncio.sleep(actual_delay) return True