Files
Neo-ZQYY/apps/backend/app/ai/rate_limiter.py
Neo 6f8f12314f feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:03:48 +08:00

74 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""限流器 — 滑动窗口内存计数器。
App1 按 user_id 限流(每用户每分钟 10 次),
App2~8 按 site_id 限流(每门店每小时 100 次)。
内存实现,单实例部署,不依赖外部存储。
"""
from __future__ import annotations
import time
from collections import deque
class RateLimiter:
"""滑动窗口内存限流器。
- check_user_rate()App1 每用户每分钟限流
- check_store_rate()App2~8 每门店每小时限流
每个 key 维护一个时间戳 deque检查时先清除过期条目
再判断窗口内请求数是否低于阈值。
"""
def __init__(self) -> None:
self._user_windows: dict[str, deque[float]] = {} # App1: user_id → 时间戳队列
self._store_windows: dict[str, deque[float]] = {} # App2~8: site_id → 时间戳队列
def _check(
self,
windows: dict[str, deque[float]],
key: str,
limit: int,
window_seconds: int,
) -> bool:
"""通用滑动窗口检查。返回 True 表示允许。"""
now = time.monotonic()
if key not in windows:
windows[key] = deque()
window = windows[key]
# 清除窗口外的过期时间戳
cutoff = now - window_seconds
while window and window[0] <= cutoff:
window.popleft()
# 判断是否超限
if len(window) >= limit:
return False
# 未超限,记录本次请求时间戳
window.append(now)
return True
def check_user_rate(
self,
user_id: str,
limit: int = 10,
window_seconds: int = 60,
) -> bool:
"""App1 每用户每分钟限流。返回 True 表示允许。"""
return self._check(self._user_windows, user_id, limit, window_seconds)
def check_store_rate(
self,
site_id: int,
limit: int = 100,
window_seconds: int = 3600,
) -> bool:
"""App2~8 每门店每小时限流。返回 True 表示允许。"""
# site_id 为 int转为 str 作为 dict key
return self._check(self._store_windows, str(site_id), limit, window_seconds)