from __future__ import annotations import asyncio import logging import time logger = logging.getLogger(__name__) class GitLabRateLimiter: """Token Bucket 限流器,默认 30 req/s(低于 GitLab 2000 req/min 限制,留有安全余量)""" def __init__(self, max_rate: float = 30.0, burst: int = 10): self._rate = max_rate self._burst = burst self._tokens = float(burst) self._last_refill = time.monotonic() self._lock = asyncio.Lock() async def acquire(self) -> None: async with self._lock: now = time.monotonic() elapsed = now - self._last_refill self._tokens = min(self._burst, self._tokens + elapsed * self._rate) self._last_refill = now if self._tokens < 1.0: wait_time = (1.0 - self._tokens) / self._rate await asyncio.sleep(wait_time) self._tokens = 0.0 else: self._tokens -= 1.0 gitlab_rate_limiter = GitLabRateLimiter(max_rate=30.0)