from __future__ import annotations import time from collections import deque RATE_LIMIT_WINDOW_SECONDS = 60 MAX_REQUESTS_PER_WINDOW = 2000 class GraphRateLimiter: def __init__( self, max_requests: int = MAX_REQUESTS_PER_WINDOW, window_seconds: int = RATE_LIMIT_WINDOW_SECONDS, ): self._max_requests = max_requests self._window_seconds = window_seconds self._timestamps: deque[float] = deque() self._remaining: int = max_requests def can_proceed(self) -> bool: self._cleanup() return len(self._timestamps) < self._max_requests def record(self) -> None: self._timestamps.append(time.monotonic()) self._cleanup() @property def remaining(self) -> int: self._cleanup() return max(0, self._max_requests - len(self._timestamps)) def _cleanup(self) -> None: cutoff = time.monotonic() - self._window_seconds while self._timestamps and self._timestamps[0] < cutoff: self._timestamps.popleft() def reset(self) -> None: self._timestamps.clear()