落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
固定窗口限流骨架。
|
||||
|
||||
本文件职责:按 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)
|
||||
Reference in New Issue
Block a user