import asyncio import logging import time from typing import Optional logger = logging.getLogger(__name__) class RateLimiter: """ Enforces minimum delay between requests to avoid throttling. Thread-safe for async use within a single event loop. """ def __init__(self, min_interval_seconds: float = 3.0): self.min_interval = min_interval_seconds self._last_request_time: Optional[float] = None self._lock = asyncio.Lock() async def acquire(self): async with self._lock: now = time.monotonic() if self._last_request_time is not None: elapsed = now - self._last_request_time wait_time = self.min_interval - elapsed if wait_time > 0: logger.info( f"Rate limiter: waiting {wait_time:.1f}s " f"(min interval: {self.min_interval}s)" ) await asyncio.sleep(wait_time) self._last_request_time = time.monotonic()