diff --git a/app.py b/app.py index ba361a09..7d88d58d 100755 --- a/app.py +++ b/app.py @@ -421,21 +421,24 @@ db = SQLAlchemy(app) mail = Mail(app) # 初始化 Flask-SocketIO(用于实时事件推送) -# 自动检测可用的异步模式,优先级:eventlet > gevent > threading +# 支持通过环境变量指定模式: SOCKETIO_ASYNC_MODE=gevent|threading def _detect_async_mode(): """检测可用的异步模式""" - try: - import eventlet - return 'eventlet' - except ImportError: - pass + # 允许通过环境变量强制指定 + forced_mode = os.environ.get('SOCKETIO_ASYNC_MODE', '').lower() + if forced_mode in ('gevent', 'threading', 'eventlet'): + return forced_mode + + # 检测 gevent 是否已被 patch(Gunicorn -k gevent 会自动 patch) try: from gevent import monkey if monkey.is_module_patched('socket'): return 'gevent' except ImportError: pass - return 'gevent' # 默认使用 gevent,Gunicorn 会 patch + + # 默认使用 threading(最稳定,配合 simple-websocket) + return 'threading' _async_mode = _detect_async_mode() print(f"📡 Flask-SocketIO async_mode: {_async_mode}") diff --git a/gunicorn_app_config.py b/gunicorn_app_config.py index ba1c0f01..fdf9ef39 100644 --- a/gunicorn_app_config.py +++ b/gunicorn_app_config.py @@ -23,15 +23,17 @@ import os bind = '0.0.0.0:5001' # Worker 进程数 -# 重要: Flask-SocketIO + eventlet 使用多 worker 时需要 Redis 消息队列 -# 单 worker + eventlet 可以处理数千并发连接(异步 I/O) -# 多 worker 需要设置环境变量: SOCKETIO_USE_QUEUE=true -workers = 1 # 默认单 worker,启用消息队列后可改为 4 +# 使用 gthread(多线程)模式,每个 worker 可启动多个线程 +# 16 核心机器建议: 4 workers × 4 threads = 16 并发处理能力 +workers = 4 -# Worker 类型 - 使用 eventlet(完整支持 WebSocket) +# 每个 worker 的线程数 +threads = 4 + +# Worker 类型 - 使用 gthread(多线程,配合 simple-websocket 支持 WebSocket) # 参考: https://flask-socketio.readthedocs.io/en/latest/deployment.html -# 注意: eventlet 模式下建议使用单 worker,多 worker 需要 Redis 消息队列 -worker_class = 'eventlet' +# gthread 是最稳定的方案,适用于 Python 3.10+ +worker_class = 'gthread' # Worker 连接数(gevent 异步模式下可以处理大量并发连接) worker_connections = 2000