update pay ui
This commit is contained in:
135
gunicorn_app_config.py
Normal file
135
gunicorn_app_config.py
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Gunicorn 配置文件 - app.py 生产环境配置(支持 Flask-SocketIO)
|
||||||
|
|
||||||
|
使用方式:
|
||||||
|
# 推荐方式: 使用 geventwebsocket 支持 WebSocket + 高并发
|
||||||
|
gunicorn -c gunicorn_app_config.py app:app
|
||||||
|
|
||||||
|
# 或者使用 eventlet(如果 gevent 有问题)
|
||||||
|
pip install eventlet
|
||||||
|
gunicorn -c gunicorn_app_config.py -k eventlet app:app
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# ==================== 基础配置 ====================
|
||||||
|
|
||||||
|
# 绑定地址和端口
|
||||||
|
bind = '0.0.0.0:5001'
|
||||||
|
|
||||||
|
# Worker 进程数(Flask-SocketIO 使用异步 worker,不需要太多)
|
||||||
|
workers = 1 # geventwebsocket 要求单 worker
|
||||||
|
|
||||||
|
# Worker 类型 - 使用 geventwebsocket 支持 WebSocket
|
||||||
|
worker_class = 'geventwebsocket.gunicorn.workers.GeventWebSocketWorker'
|
||||||
|
|
||||||
|
# Worker 连接数(gevent 异步模式下可以处理大量并发连接)
|
||||||
|
worker_connections = 1000
|
||||||
|
|
||||||
|
# 每个 worker 处理的最大请求数,超过后重启(防止内存泄漏)
|
||||||
|
max_requests = 10000
|
||||||
|
max_requests_jitter = 1000
|
||||||
|
|
||||||
|
# ==================== 超时配置 ====================
|
||||||
|
|
||||||
|
# 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 = 'info'
|
||||||
|
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("=" * 60)
|
||||||
|
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("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
|
def when_ready(server):
|
||||||
|
"""服务准备就绪时调用"""
|
||||||
|
print("✅ Gunicorn 服务准备就绪! WebSocket 支持已启用")
|
||||||
|
|
||||||
|
|
||||||
|
def post_worker_init(worker):
|
||||||
|
"""Worker 初始化完成后调用"""
|
||||||
|
# gevent monkey patching 在这里自动完成
|
||||||
|
print(f"✅ Worker {worker.pid} 已初始化 (gevent 异步模式)")
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
|
||||||
30
start_production.bat
Normal file
30
start_production.bat
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
@echo off
|
||||||
|
REM 生产环境启动脚本 - app.py (Flask + SocketIO)
|
||||||
|
REM 使用 Gunicorn + geventwebsocket 支持高并发
|
||||||
|
REM 注意: Windows 下使用 waitress 替代 Gunicorn
|
||||||
|
|
||||||
|
echo ============================================
|
||||||
|
echo 启动 VF React 生产服务器 (Windows)
|
||||||
|
echo ============================================
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
|
||||||
|
REM 检查 waitress(Windows 兼容的 WSGI 服务器)
|
||||||
|
python -c "import waitress" 2>nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo 正在安装 waitress...
|
||||||
|
pip install waitress
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo 启动服务器...
|
||||||
|
echo 端口: 5001
|
||||||
|
echo 线程数: 8
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Windows 下使用 waitress 替代 gunicorn
|
||||||
|
REM 注意:waitress 不支持 WebSocket,建议在 Linux 服务器上部署生产环境
|
||||||
|
python -c "from waitress import serve; from app import app; print('Starting...'); serve(app, host='0.0.0.0', port=5001, threads=8)"
|
||||||
|
|
||||||
|
pause
|
||||||
|
|
||||||
64
start_production.sh
Normal file
64
start_production.sh
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 生产环境启动脚本 - app.py (Flask + SocketIO)
|
||||||
|
# 使用 Gunicorn + geventwebsocket 支持高并发
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 颜色输出
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
echo -e "${GREEN}🚀 启动 VF React 生产服务器${NC}"
|
||||||
|
echo -e "${GREEN}============================================${NC}"
|
||||||
|
|
||||||
|
# 切换到脚本所在目录
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
# 检查 Python 环境
|
||||||
|
if ! command -v python3 &> /dev/null; then
|
||||||
|
echo -e "${RED}❌ Python3 未安装${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查 gunicorn
|
||||||
|
if ! command -v gunicorn &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}⚠️ Gunicorn 未安装,正在安装...${NC}"
|
||||||
|
pip install gunicorn
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查必要的依赖
|
||||||
|
echo -e "${GREEN}📦 检查依赖...${NC}"
|
||||||
|
python3 -c "import gevent; import geventwebsocket" 2>/dev/null || {
|
||||||
|
echo -e "${RED}❌ 缺少 gevent 或 geventwebsocket${NC}"
|
||||||
|
echo "运行: pip install gevent gevent-websocket"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 检查 Redis
|
||||||
|
echo -e "${GREEN}🔍 检查 Redis 连接...${NC}"
|
||||||
|
python3 -c "import redis; r=redis.Redis(); r.ping()" 2>/dev/null || {
|
||||||
|
echo -e "${YELLOW}⚠️ Redis 连接失败,请确保 Redis 正在运行${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 停止旧进程(如果存在)
|
||||||
|
if [ -f /tmp/gunicorn_app.pid ]; then
|
||||||
|
OLD_PID=$(cat /tmp/gunicorn_app.pid)
|
||||||
|
if kill -0 $OLD_PID 2>/dev/null; then
|
||||||
|
echo -e "${YELLOW}🛑 停止旧进程 (PID: $OLD_PID)...${NC}"
|
||||||
|
kill -TERM $OLD_PID
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 启动服务器
|
||||||
|
echo -e "${GREEN}🚀 启动 Gunicorn + Flask-SocketIO...${NC}"
|
||||||
|
echo -e "${GREEN} 配置: gunicorn_app_config.py${NC}"
|
||||||
|
echo -e "${GREEN} 端口: 5001${NC}"
|
||||||
|
echo -e "${GREEN} Worker: GeventWebSocketWorker${NC}"
|
||||||
|
|
||||||
|
# 使用 gunicorn 启动(支持 WebSocket 的高并发模式)
|
||||||
|
exec gunicorn -c gunicorn_app_config.py app:app
|
||||||
|
|
||||||
Reference in New Issue
Block a user