"""限流准入封装: 后端故障必须报错而非放行(降级方向铁律)。 非降级设计说明: 缓存/遥测挂 → 静默;限流挂 → 若放行,多 worker 会同时 失去闸门直接击穿网关,故一律 GovernanceBackendError 上抛。 """ from __future__ import annotations from typing import TYPE_CHECKING from polygateway.errors import GovernanceBackendError, SourceNotConfiguredError if TYPE_CHECKING: from polygateway.ports import Permit, RateLimiter from polygateway.types import SourceConfig, SourceStats class QuotaGate: """RetryMW 面向限流后端的唯一入口;包装一切后端异常。""" def __init__(self, limiter: RateLimiter, *, scope: str) -> None: self._limiter = limiter # 后端故障即 scope 级不可用,异常须携 scope 供调用方定位(issue #7 §3.3) self._scope = scope async def try_acquire(self, source: SourceConfig) -> Permit | None: try: return await self._limiter.try_acquire(source.name, source.effective_est_tokens()) except (GovernanceBackendError, SourceNotConfiguredError): raise except Exception as exc: raise GovernanceBackendError( f"限流后端故障(try_acquire): {exc}", scope=self._scope ) from exc async def stats(self, source: SourceConfig) -> SourceStats: try: return await self._limiter.source_stats(source.name) except (GovernanceBackendError, SourceNotConfiguredError): raise except Exception as exc: raise GovernanceBackendError( f"限流后端故障(source_stats): {exc}", scope=self._scope ) from exc async def mark_progress(self) -> None: try: await self._limiter.mark_progress() except (GovernanceBackendError, SourceNotConfiguredError): raise except Exception as exc: raise GovernanceBackendError( f"限流后端故障(mark_progress): {exc}", scope=self._scope ) from exc async def progress_age_s(self) -> float: try: return await self._limiter.progress_age_s() except (GovernanceBackendError, SourceNotConfiguredError): raise except Exception as exc: raise GovernanceBackendError( f"限流后端故障(progress_age_s): {exc}", scope=self._scope ) from exc