11.25 超时设置、连接设置
This commit is contained in:
parent
0fc892f819
commit
80df0e377a
@ -1,7 +1,8 @@
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask import current_app, jsonify, stream_with_context, Response
|
from flask import current_app, jsonify, stream_with_context, Response, request
|
||||||
|
|
||||||
|
|
||||||
class ExecutionTimeoutMonitor:
|
class ExecutionTimeoutMonitor:
|
||||||
"""监控请求执行时间,超时后释放信号量"""
|
"""监控请求执行时间,超时后释放信号量"""
|
||||||
@ -26,17 +27,21 @@ class ExecutionTimeoutMonitor:
|
|||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
def require_connection_limit(timeout=900):
|
def require_connection_limit(timeout=900):
|
||||||
"""装饰器:确保路由使用连接限制,并监控请求执行时间"""
|
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
limiter = getattr(current_app, 'connection_limiter', None)
|
blueprint = request.blueprint
|
||||||
|
limiter = current_app.connection_limiters.get(blueprint, current_app.connection_limiters.get('default'))
|
||||||
if limiter is None:
|
if limiter is None:
|
||||||
current_app.logger.error("ConnectionLimiter 未初始化")
|
current_app.logger.error(f"未为蓝图 '{blueprint}' 配置 ConnectionLimiter,并且未设置默认限流器。")
|
||||||
return jsonify({'error': 'Server configuration error'}), 500
|
return jsonify({'error': '服务器配置错误'}), 500
|
||||||
|
|
||||||
|
# 获取信号量(阻塞)
|
||||||
|
acquired = limiter.semaphore.acquire(blocking=True)
|
||||||
|
if not acquired:
|
||||||
|
current_app.logger.warning("并发连接过多")
|
||||||
|
return jsonify({'error': '并发连接过多'}), 429
|
||||||
|
|
||||||
# 阻塞方式获取信号量
|
|
||||||
limiter.semaphore.acquire()
|
|
||||||
try:
|
try:
|
||||||
# 启动执行超时监控器
|
# 启动执行超时监控器
|
||||||
monitor = ExecutionTimeoutMonitor(timeout, limiter.semaphore)
|
monitor = ExecutionTimeoutMonitor(timeout, limiter.semaphore)
|
||||||
@ -49,8 +54,7 @@ def require_connection_limit(timeout=900):
|
|||||||
try:
|
try:
|
||||||
for item in generator:
|
for item in generator:
|
||||||
if monitor.is_timeout:
|
if monitor.is_timeout:
|
||||||
# 如果已超时,终止生成器执行
|
current_app.logger.error("请求执行时间超过限制并被终止。")
|
||||||
current_app.logger.error("Request exceeded execution time and was terminated.")
|
|
||||||
break
|
break
|
||||||
yield item
|
yield item
|
||||||
finally:
|
finally:
|
||||||
@ -60,8 +64,8 @@ def require_connection_limit(timeout=900):
|
|||||||
return Response(generator_wrapper(), mimetype='text/event-stream')
|
return Response(generator_wrapper(), mimetype='text/event-stream')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
limiter.semaphore.release() # 异常时释放信号量
|
limiter.semaphore.release() # 异常时释放信号量
|
||||||
current_app.logger.error(f"Exception in route: {e}")
|
current_app.logger.error(f"路由处理异常: {e}")
|
||||||
return jsonify({'error': 'Internal server error'}), 500
|
return jsonify({'error': '内部服务器错误'}), 500
|
||||||
return wrapped
|
return wrapped
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# flask_app/routes/get_deviation.py
|
# flask_app/routes/get_deviation.py
|
||||||
|
import time
|
||||||
|
|
||||||
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
|
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
|
||||||
import json
|
import json
|
||||||
@ -6,13 +7,11 @@ import os
|
|||||||
from flask_app.main.download import download_file
|
from flask_app.main.download import download_file
|
||||||
from flask_app.general.post_processing import outer_post_processing
|
from flask_app.general.post_processing import outer_post_processing
|
||||||
from flask_app.general.接口_技术偏离表 import get_tech_and_business_deviation
|
from flask_app.general.接口_技术偏离表 import get_tech_and_business_deviation
|
||||||
|
|
||||||
from flask_app.logger_setup import CSTFormatter
|
|
||||||
|
|
||||||
from flask_app.routes.utils import generate_deviation_response, validate_request
|
from flask_app.routes.utils import generate_deviation_response, validate_request
|
||||||
|
from flask_app.ConnectionLimiter import require_connection_limit
|
||||||
get_deviation_bp = Blueprint('get_deviation', __name__)
|
get_deviation_bp = Blueprint('get_deviation', __name__)
|
||||||
@get_deviation_bp.route('/get_deviation', methods=['POST'])
|
@get_deviation_bp.route('/get_deviation', methods=['POST'])
|
||||||
|
@require_connection_limit(timeout=700)
|
||||||
def get_deviation():
|
def get_deviation():
|
||||||
logger = g.logger
|
logger = g.logger
|
||||||
unique_id = g.unique_id
|
unique_id = g.unique_id
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# flask_app/routes/little_zbparse.py
|
# flask_app/routes/little_zbparse.py
|
||||||
|
import time
|
||||||
|
|
||||||
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
|
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from flask_app.ConnectionLimiter import require_connection_limit
|
||||||
from flask_app.main.download import download_file
|
from flask_app.main.download import download_file
|
||||||
from flask_app.general.post_processing import outer_post_processing
|
from flask_app.general.post_processing import outer_post_processing
|
||||||
from flask_app.general.接口_小解析 import little_parse_main
|
from flask_app.general.接口_小解析 import little_parse_main
|
||||||
@ -14,6 +16,7 @@ from flask_app.routes.utils import validate_request
|
|||||||
|
|
||||||
little_zbparse_bp = Blueprint('little_zbparse', __name__)
|
little_zbparse_bp = Blueprint('little_zbparse', __name__)
|
||||||
@little_zbparse_bp.route('/little_zbparse', methods=['POST'])
|
@little_zbparse_bp.route('/little_zbparse', methods=['POST'])
|
||||||
|
@require_connection_limit(timeout=300)
|
||||||
def little_zbparse():
|
def little_zbparse():
|
||||||
logger = g.logger
|
logger = g.logger
|
||||||
file_url, zb_type = validate_request()
|
file_url, zb_type = validate_request()
|
||||||
|
@ -17,7 +17,7 @@ from flask_app.ConnectionLimiter import require_connection_limit
|
|||||||
upload_bp = Blueprint('upload', __name__)
|
upload_bp = Blueprint('upload', __name__)
|
||||||
|
|
||||||
@upload_bp.route('/upload', methods=['POST'])
|
@upload_bp.route('/upload', methods=['POST'])
|
||||||
@require_connection_limit(timeout=900)
|
@require_connection_limit(timeout=800)
|
||||||
def zbparse():
|
def zbparse():
|
||||||
logger = g.logger
|
logger = g.logger
|
||||||
try:
|
try:
|
||||||
@ -38,7 +38,6 @@ def zbparse():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Unexpected exception: ' + str(e))
|
logger.error('Unexpected exception: ' + str(e))
|
||||||
return jsonify({'error': 'Internal server error'}), 500
|
return jsonify({'error': 'Internal server error'}), 500
|
||||||
|
|
||||||
def process_and_stream(file_url, zb_type):
|
def process_and_stream(file_url, zb_type):
|
||||||
"""
|
"""
|
||||||
下载文件并进行处理,支持工程标和货物标的处理。
|
下载文件并进行处理,支持工程标和货物标的处理。
|
||||||
|
@ -13,7 +13,8 @@ from flask_app.routes.test_zbparse import test_zbparse_bp
|
|||||||
class FlaskAppWithLimiter(Flask):
|
class FlaskAppWithLimiter(Flask):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.connection_limiter = ConnectionLimiter(max_connections=10)
|
# 初始化一个字典来存储每个蓝图的限流器
|
||||||
|
self.connection_limiters = {}
|
||||||
def create_app():
|
def create_app():
|
||||||
app = FlaskAppWithLimiter(__name__)
|
app = FlaskAppWithLimiter(__name__)
|
||||||
|
|
||||||
@ -47,7 +48,9 @@ def create_app():
|
|||||||
app.register_blueprint(little_zbparse_bp)
|
app.register_blueprint(little_zbparse_bp)
|
||||||
app.register_blueprint(upload_bp)
|
app.register_blueprint(upload_bp)
|
||||||
app.register_blueprint(test_zbparse_bp)
|
app.register_blueprint(test_zbparse_bp)
|
||||||
|
app.connection_limiters['upload'] = ConnectionLimiter(max_connections=7)
|
||||||
|
app.connection_limiters['get_deviation'] = ConnectionLimiter(max_connections=7)
|
||||||
|
app.connection_limiters['default'] = ConnectionLimiter(max_connections=10)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
#TODO:培训要求、总体要求、进度要求、'建设要求'到技术要求中,归类到其他要求中
|
#TODO:培训要求、总体要求、进度要求、'建设要求'到技术要求中,归类到其他要求中
|
||||||
|
Loading…
x
Reference in New Issue
Block a user