2024-11-25 16:24:38 +08:00
|
|
|
|
# flask_app/ConnectionLimiter.py
|
|
|
|
|
|
2024-11-25 10:13:39 +08:00
|
|
|
|
import threading
|
2024-11-25 14:38:58 +08:00
|
|
|
|
import time
|
2024-11-25 09:15:56 +08:00
|
|
|
|
from functools import wraps
|
2024-11-25 16:24:38 +08:00
|
|
|
|
from flask import current_app, jsonify, g, request, Response, stream_with_context
|
2024-11-25 09:15:56 +08:00
|
|
|
|
|
2024-11-25 14:38:58 +08:00
|
|
|
|
class ExecutionTimeoutMonitor:
|
|
|
|
|
"""监控请求执行时间,超时后释放信号量"""
|
|
|
|
|
def __init__(self, timeout, semaphore):
|
|
|
|
|
self.timeout = timeout
|
|
|
|
|
self.semaphore = semaphore
|
|
|
|
|
self.is_timeout = False
|
|
|
|
|
self.thread = threading.Thread(target=self._monitor)
|
|
|
|
|
self.thread.daemon = True
|
2024-11-25 09:15:56 +08:00
|
|
|
|
|
2024-11-25 14:38:58 +08:00
|
|
|
|
def _monitor(self):
|
2024-11-25 16:24:38 +08:00
|
|
|
|
"""等待指定时间后标记为超时并释放信号量"""
|
2024-11-25 14:38:58 +08:00
|
|
|
|
time.sleep(self.timeout)
|
|
|
|
|
self.is_timeout = True
|
|
|
|
|
self.semaphore.release() # 超时后释放信号量
|
2024-11-25 16:24:38 +08:00
|
|
|
|
current_app.logger.error(f"请求执行时间超过 {self.timeout} 秒并被终止。")
|
2024-11-25 09:15:56 +08:00
|
|
|
|
|
2024-11-25 14:38:58 +08:00
|
|
|
|
def start(self):
|
|
|
|
|
self.thread.start()
|
2024-11-25 10:13:39 +08:00
|
|
|
|
|
2024-11-25 16:24:38 +08:00
|
|
|
|
class ConnectionLimiter:
|
|
|
|
|
def __init__(self, max_connections=1):
|
|
|
|
|
self.semaphore = threading.Semaphore(max_connections)
|
|
|
|
|
|
2024-11-25 14:38:58 +08:00
|
|
|
|
def require_connection_limit(timeout=900):
|
2024-11-25 16:24:38 +08:00
|
|
|
|
"""装饰器:确保路由使用连接限制,并监控请求执行时间"""
|
2024-11-25 14:38:58 +08:00
|
|
|
|
def decorator(f):
|
2024-11-25 09:15:56 +08:00
|
|
|
|
@wraps(f)
|
2024-11-25 10:13:39 +08:00
|
|
|
|
def wrapped(*args, **kwargs):
|
2024-11-25 16:04:53 +08:00
|
|
|
|
blueprint = request.blueprint
|
|
|
|
|
limiter = current_app.connection_limiters.get(blueprint, current_app.connection_limiters.get('default'))
|
2024-11-25 14:38:58 +08:00
|
|
|
|
if limiter is None:
|
2024-11-25 16:04:53 +08:00
|
|
|
|
current_app.logger.error(f"未为蓝图 '{blueprint}' 配置 ConnectionLimiter,并且未设置默认限流器。")
|
|
|
|
|
return jsonify({'error': '服务器配置错误'}), 500
|
|
|
|
|
|
|
|
|
|
acquired = limiter.semaphore.acquire(blocking=True)
|
|
|
|
|
if not acquired:
|
|
|
|
|
current_app.logger.warning("并发连接过多")
|
|
|
|
|
return jsonify({'error': '并发连接过多'}), 429
|
2024-11-25 14:38:58 +08:00
|
|
|
|
|
2024-11-25 16:24:38 +08:00
|
|
|
|
# 启动执行超时监控器
|
|
|
|
|
monitor = ExecutionTimeoutMonitor(timeout, limiter.semaphore)
|
|
|
|
|
monitor.start()
|
|
|
|
|
|
|
|
|
|
# 将限流器和监控器存储在 g 中,以便在 teardown_request 中释放信号量
|
|
|
|
|
g.limiter = limiter
|
|
|
|
|
g.monitor = monitor
|
|
|
|
|
|
2024-11-25 09:15:56 +08:00
|
|
|
|
try:
|
2024-11-25 16:24:38 +08:00
|
|
|
|
result = f(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
if isinstance(result, Response):
|
|
|
|
|
# 对于普通的 Response 对象,不需要额外处理
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
elif hasattr(result, '__iter__'):
|
|
|
|
|
# 如果返回的是生成器,按原有逻辑处理
|
|
|
|
|
@stream_with_context
|
|
|
|
|
def generator_wrapper():
|
|
|
|
|
try:
|
|
|
|
|
for item in result:
|
|
|
|
|
if monitor.is_timeout:
|
|
|
|
|
current_app.logger.error("请求执行时间超过限制并被终止。")
|
|
|
|
|
break
|
|
|
|
|
yield item
|
|
|
|
|
finally:
|
|
|
|
|
if not monitor.is_timeout:
|
|
|
|
|
limiter.semaphore.release()
|
|
|
|
|
|
|
|
|
|
return Response(generator_wrapper(), mimetype='text/event-stream')
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
# 对于其他类型的响应,直接返回
|
|
|
|
|
return result
|
|
|
|
|
|
2024-11-25 14:38:58 +08:00
|
|
|
|
except Exception as e:
|
2024-11-25 16:24:38 +08:00
|
|
|
|
limiter.semaphore.release()
|
2024-11-25 16:04:53 +08:00
|
|
|
|
current_app.logger.error(f"路由处理异常: {e}")
|
|
|
|
|
return jsonify({'error': '内部服务器错误'}), 500
|
2024-11-25 16:24:38 +08:00
|
|
|
|
|
2024-11-25 10:13:39 +08:00
|
|
|
|
return wrapped
|
2024-11-25 14:38:58 +08:00
|
|
|
|
return decorator
|