# -----------------------------------------------------------
# Astra - WhatsApp Client Framework
# Licensed under the Apache License 2.0.
# -----------------------------------------------------------
"""
This module provides a strategy for retrying failed connections.
It uses exponential backoff to avoid overwhelming the server.
"""
import random
import logging
from typing import Optional
from ..constants import MAX_RECONNECT_ATTEMPTS, RECONNECT_DELAY_MAX
logger = logging.getLogger("Sync")
[docs]
class RetryStrategy:
"""
A resilient retry manager for connection recovery.
Implements exponential backoff with random jitter to ensure
reconnections happen in a nature-friendly way.
"""
def __init__(
self,
base_delay: float = 2.0,
max_delay: float = RECONNECT_DELAY_MAX,
max_attempts: int = MAX_RECONNECT_ATTEMPTS
):
self.base_delay = base_delay
self.max_delay = max_delay
self.max_attempts = max_attempts
self._current_attempt = 0
[docs]
def reset(self):
"""Resets the attempt counter (usually called on successful connection)."""
if self._current_attempt > 0:
logger.info("Connection stable. Resetting retry policy.")
self._current_attempt = 0
[docs]
def next_delay(self) -> Optional[float]:
"""
Calculates the wait time for the next reconnection attempt.
Returns:
The delay in seconds, or None if the retry limit is reached.
"""
if self._current_attempt >= self.max_attempts:
return None
# Exponential growth: 2, 4, 8, 16...
backoff = min(self.base_delay * (2 ** self._current_attempt), self.max_delay)
# Add Jitter (0.7 to 1.3 variant) to prevent thundering herd
delay = backoff * random.uniform(0.7, 1.3)
self._current_attempt += 1
logger.debug(f"Retrying connection (Attempt {self._current_attempt}/{self.max_attempts}) in {delay:.2f}s")
return delay
@property
def current_attempt(self) -> int:
return self._current_attempt