""" 固定窗口限流骨架。 本文件职责:按 scope 计数;超限返回可重试,不写主账失败态。 线程:可在出站/API 路径调用;禁止在限流键上做六态。 """ from __future__ import annotations import logging from dataclasses import dataclass from agent.redis_coord.client import RedisClient from agent.redis_coord.keys import RATE_LIMIT logger = logging.getLogger(__name__) @dataclass class RateLimitResult: """限流判定结果。""" allowed: bool count: int limit: int scope: str def allow( client: RedisClient, *, scope: str, limit: int, window_seconds: int = 60, ) -> RateLimitResult: """ 固定窗口:INCR + 首次 EXPIRE。 scope 示例:outbound:wecom / api:global / user:{sender_id} """ key = client.key(RATE_LIMIT, scope) count = int(client.raw.incr(key)) if count == 1: client.raw.expire(key, window_seconds) allowed = count <= limit if not allowed: logger.info( "限流触发 scope=%s count=%s limit=%s", scope, count, limit, ) return RateLimitResult(allowed=allowed, count=count, limit=limit, scope=scope)