35 lines
1.2 KiB
Python
35 lines
1.2 KiB
Python
"""Rate limiting for TfL API requests."""
|
|
|
|
import asyncio
|
|
import warnings
|
|
|
|
from .config import REQUESTS_PER_MIN
|
|
|
|
|
|
class RateLimiter:
|
|
"""Rate limiter enforcing max requests per minute."""
|
|
|
|
def __init__(self):
|
|
self.request_times: list[float] = []
|
|
self._lock = asyncio.Lock()
|
|
|
|
async def acquire(self):
|
|
"""Wait until we can make a request within rate limits."""
|
|
async with self._lock:
|
|
now = asyncio.get_event_loop().time()
|
|
cutoff = now - 10.0 # 10 seconds
|
|
self.request_times = [t for t in self.request_times if t > cutoff]
|
|
|
|
if (
|
|
len(self.request_times) >= REQUESTS_PER_MIN // 6
|
|
): # we look at it every 10 seconds instead of minutes
|
|
wait_time = self.request_times[0] - cutoff
|
|
if wait_time > 0:
|
|
warnings.warn(
|
|
f"Rate limit reached ({REQUESTS_PER_MIN}/min), "
|
|
f"waiting {wait_time:.1f}s",
|
|
stacklevel=1,
|
|
)
|
|
await asyncio.sleep(wait_time)
|
|
|
|
self.request_times.append(asyncio.get_event_loop().time())
|