Files
inquiry_robot/inquiry-agent/agent/redis_coord/rate_limit.py
T

54 lines
1.2 KiB
Python

"""
固定窗口限流骨架。
本文件职责:按 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)