Files
vf_react/gunicorn_app_config.py
2025-12-11 23:02:48 +08:00

152 lines
4.7 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.

# -*- coding: utf-8 -*-
"""
Gunicorn 配置文件 - app.py 生产环境配置(支持 Flask-SocketIO + WebSocket + 多进程)
使用方式:
# 推荐方式: 使用此配置文件启动(多 Worker 模式)
gunicorn -c gunicorn_app_config.py app:app
# 单 Worker 调试模式:
gunicorn -c gunicorn_app_config.py -w 1 app:app
多进程架构说明:
- Flask Session 使用 Redis 存储db=1所有 Worker 共享
- SocketIO 使用 Redis 消息队列db=2跨 Worker 消息同步
- 微信登录状态使用 Redis 存储db=0所有 Worker 共享
"""
import os
# ==================== 基础配置 ====================
# 绑定地址和端口
bind = '0.0.0.0:5001'
# Worker 进程数
# 对于 16 核心机器,使用 4-8 个 gevent workers 即可(每个可处理数千并发)
# 建议: min(8, CPU_CORES / 2) 因为 gevent 本身是异步的,不需要太多进程
workers = 4 # 4 个 gevent workers每个可处理 2000 并发连接 = 8000 总并发
# Worker 类型 - 使用 gevent新版 Flask-SocketIO 不需要 geventwebsocket
# 参考: https://flask-socketio.readthedocs.io/en/latest/deployment.html
worker_class = 'gevent'
# Worker 连接数gevent 异步模式下可以处理大量并发连接)
worker_connections = 2000
# 每个 worker 处理的最大请求数(防止内存泄漏)
# 对于 WebSocket 长连接,设置一个较大的值,不能是 0否则内存泄漏无法恢复
max_requests = 10000 # 处理 10000 个请求后重启 worker
max_requests_jitter = 1000 # 随机抖动,避免所有 worker 同时重启
# ==================== 超时配置 ====================
# Worker 超时时间WebSocket 需要长连接,设大一些
timeout = 300
# 优雅关闭超时时间(秒)
graceful_timeout = 30
# 保持连接超时时间(秒)
keepalive = 65
# ==================== SSL 配置 ====================
cert_file = '/etc/letsencrypt/live/valuefrontier.cn/fullchain.pem'
key_file = '/etc/letsencrypt/live/valuefrontier.cn/privkey.pem'
if os.path.exists(cert_file) and os.path.exists(key_file):
certfile = cert_file
keyfile = key_file
# ==================== 日志配置 ====================
accesslog = '-'
errorlog = '-'
loglevel = 'debug' # 调试时用 debug正常运行用 info
capture_output = True # 捕获 print 输出到日志
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)sμs'
# ==================== 进程管理 ====================
daemon = False
pidfile = '/tmp/gunicorn_app.pid'
proc_name = 'vf_react_app'
# 不预加载应用,确保 gevent monkey patch 正确
preload_app = False
# ==================== Hook 函数 ====================
def on_starting(server):
"""服务器启动时调用"""
print("=" * 70)
print("🚀 Gunicorn + Flask-SocketIO 多进程服务器正在启动...")
print(f" Workers: {server.app.cfg.workers}")
print(f" Worker Class: {server.app.cfg.worker_class}")
print(f" Bind: {server.app.cfg.bind}")
print(f" Worker Connections: {server.app.cfg.worker_connections}")
print(f" Max Requests: {server.app.cfg.max_requests}")
print("-" * 70)
print(" Redis 存储分配:")
print(" - db=0: 微信登录状态")
print(" - db=1: Flask Session")
print(" - db=2: SocketIO 消息队列")
print("=" * 70)
def when_ready(server):
"""服务准备就绪时调用"""
print(f"✅ Gunicorn 服务准备就绪! {server.app.cfg.workers} 个 Worker 已启动")
print(" 多进程支持已启用 (Redis Session + SocketIO Message Queue)")
def post_worker_init(worker):
"""Worker 初始化完成后调用"""
# gevent monkey patching 在这里自动完成
print(f"✅ Worker {worker.pid} 已初始化 (gevent 异步模式, 可处理 2000 并发连接)")
def worker_abort(worker):
"""Worker 收到 SIGABRT 信号时调用(超时)"""
print(f"⚠️ Worker {worker.pid} 超时被终止,正在重启...")
def on_exit(server):
"""服务器退出时调用"""
print("🛑 Gunicorn 服务器已关闭")
# ==================== systemd 服务配置示例 ====================
"""
保存为 /etc/systemd/system/vf_react.service:
[Unit]
Description=VF React Flask Application with SocketIO
After=network.target redis.service mysql.service
[Service]
User=root
Group=root
WorkingDirectory=/path/to/vf_react
Environment="PATH=/path/to/venv/bin"
ExecStart=/path/to/venv/bin/gunicorn -c gunicorn_app_config.py app:app
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=5
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
启用服务:
sudo systemctl daemon-reload
sudo systemctl enable vf_react
sudo systemctl start vf_react
sudo systemctl status vf_react
查看日志:
sudo journalctl -u vf_react -f
"""