243 lines
6.5 KiB
Bash
243 lines
6.5 KiB
Bash
#!/bin/bash
|
||
|
||
# 配置参数
|
||
PYTHON_ENV="/home/work/keyword_crawl/venv" # Python虚拟环境
|
||
APP_DIR="/home/work/ai_wht" # 应用代码目录
|
||
APP_FILE="$APP_DIR/flask_wht_server_api.py" # 应用文件
|
||
APP_NAME="flask_wht_server_api:app" # Gunicorn应用名称
|
||
PORT="8216"
|
||
WORKERS="6"
|
||
LOG_FILE="$APP_DIR/log10bjh_wht_server_api_$(date +%y%m%d%H%M).log"
|
||
PID_FILE="/tmp/gunicorn_wht_server_api.pid"
|
||
TIMEOUT=120
|
||
|
||
echo "=========================================="
|
||
echo "启动 Flask 应用服务器"
|
||
echo "=========================================="
|
||
echo "Python环境: $PYTHON_ENV"
|
||
echo "应用目录: $APP_DIR"
|
||
echo "应用文件: $(basename $APP_FILE)"
|
||
echo "端口: $PORT"
|
||
echo "工作进程: $WORKERS"
|
||
echo "日志文件: $LOG_FILE"
|
||
echo "=========================================="
|
||
|
||
# 检查应用文件是否存在
|
||
if [ ! -f "$APP_FILE" ]; then
|
||
echo "❌ 错误: 找不到应用文件 $APP_FILE"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查虚拟环境
|
||
if [ ! -f "$PYTHON_ENV/bin/activate" ]; then
|
||
echo "❌ 错误: 找不到虚拟环境 $PYTHON_ENV"
|
||
exit 1
|
||
fi
|
||
|
||
# 切换到应用目录
|
||
cd "$APP_DIR" || {
|
||
echo "❌ 错误: 无法进入应用目录 $APP_DIR"
|
||
exit 1
|
||
}
|
||
|
||
echo "当前工作目录: $(pwd)"
|
||
echo "目录内容:"
|
||
ls -la *.py
|
||
|
||
# 激活虚拟环境
|
||
echo ""
|
||
echo "激活虚拟环境..."
|
||
source "$PYTHON_ENV/bin/activate"
|
||
|
||
echo "Python路径: $(which python)"
|
||
echo "Python版本: $(python --version 2>&1)"
|
||
|
||
# 检查gunicorn
|
||
if ! command -v gunicorn &> /dev/null; then
|
||
echo "❌ 错误: gunicorn 未安装"
|
||
echo "请执行: pip install gunicorn"
|
||
exit 1
|
||
fi
|
||
|
||
echo "Gunicorn路径: $(which gunicorn)"
|
||
echo "Gunicorn版本: $(gunicorn --version 2>&1)"
|
||
|
||
# 添加应用目录到Python路径
|
||
export PYTHONPATH="$APP_DIR:$PYTHONPATH"
|
||
echo "PYTHONPATH: $PYTHONPATH"
|
||
|
||
# 测试导入
|
||
echo ""
|
||
echo "测试应用导入..."
|
||
python -c "
|
||
import sys
|
||
print('Python路径:')
|
||
for p in sys.path[:5]:
|
||
print(f' {p}')
|
||
print('...')
|
||
try:
|
||
# 尝试导入
|
||
import importlib.util
|
||
import os
|
||
|
||
module_name = 'flask_wht_server_api'
|
||
file_path = '$APP_FILE'
|
||
|
||
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
||
module = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(module)
|
||
print('✅ 成功加载模块')
|
||
|
||
# 检查是否有app对象
|
||
if hasattr(module, 'app'):
|
||
print('✅ 找到 Flask app 对象')
|
||
app = module.app
|
||
print(f' App名称: {app.name if hasattr(app, "name") else "未知"}')
|
||
else:
|
||
# 检查其他可能的名称
|
||
for attr_name in ['application', 'flask_app', 'create_app']:
|
||
if hasattr(module, attr_name):
|
||
print(f'✅ 找到 {attr_name} 对象')
|
||
break
|
||
else:
|
||
print('⚠️ 未找到标准的Flask应用对象')
|
||
print('可用的属性:', [a for a in dir(module) if not a.startswith('_')][:10])
|
||
|
||
except Exception as e:
|
||
print(f'❌ 导入失败: {e}')
|
||
import traceback
|
||
traceback.print_exc()
|
||
"
|
||
|
||
# (1) 停止现有进程
|
||
echo ""
|
||
echo "停止现有进程..."
|
||
|
||
# 通过PID文件停止
|
||
if [ -f "$PID_FILE" ]; then
|
||
OLD_PID=$(cat "$PID_FILE" 2>/dev/null)
|
||
if [ -n "$OLD_PID" ] && kill -0 "$OLD_PID" 2>/dev/null; then
|
||
echo "停止进程 $OLD_PID..."
|
||
kill "$OLD_PID"
|
||
sleep 3
|
||
if kill -0 "$OLD_PID" 2>/dev/null; then
|
||
echo "强制停止进程 $OLD_PID..."
|
||
kill -9 "$OLD_PID"
|
||
fi
|
||
fi
|
||
rm -f "$PID_FILE"
|
||
fi
|
||
|
||
# 通过进程名停止
|
||
echo "查找相关进程..."
|
||
PIDS=$(ps aux | grep -E "(gunicorn.*flask_wht_server_api|python.*flask_wht_server_api)" | grep -v grep | awk '{print $2}')
|
||
if [ -n "$PIDS" ]; then
|
||
echo "停止进程: $PIDS"
|
||
for PID in $PIDS; do
|
||
kill "$PID" 2>/dev/null
|
||
sleep 1
|
||
if kill -0 "$PID" 2>/dev/null; then
|
||
kill -9 "$PID" 2>/dev/null
|
||
fi
|
||
done
|
||
fi
|
||
|
||
sleep 2
|
||
|
||
# 检查端口占用
|
||
if lsof -ti:$PORT >/dev/null 2>&1; then
|
||
echo "⚠️ 端口 $PORT 仍被占用,强制清理..."
|
||
lsof -ti:$PORT | xargs kill -9 2>/dev/null
|
||
sleep 2
|
||
fi
|
||
|
||
# (2) 启动新进程
|
||
echo ""
|
||
echo "启动 Gunicorn 服务器..."
|
||
|
||
# 构建启动命令
|
||
GUNICORN_CMD="gunicorn"
|
||
CMD_ARGS="-w $WORKERS
|
||
-b 0.0.0.0:$PORT
|
||
--pid $PID_FILE
|
||
--timeout $TIMEOUT
|
||
--access-logfile $APP_DIR/access.log
|
||
--error-logfile $APP_DIR/error.log
|
||
--log-level info
|
||
--preload
|
||
'$APP_NAME'"
|
||
|
||
echo "执行命令:"
|
||
echo "$GUNICORN_CMD $CMD_ARGS"
|
||
|
||
# 启动服务(后台运行)
|
||
nohup $GUNICORN_CMD -w $WORKERS \
|
||
-b 0.0.0.0:$PORT \
|
||
--pid $PID_FILE \
|
||
--timeout $TIMEOUT \
|
||
--access-logfile "$APP_DIR/access.log" \
|
||
--error-logfile "$APP_DIR/error.log" \
|
||
--log-level info \
|
||
--preload \
|
||
"$APP_NAME" >> "$LOG_FILE" 2>&1 &
|
||
|
||
# 等待启动
|
||
echo -n "等待服务启动"
|
||
for i in {1..20}; do
|
||
if [ -f "$PID_FILE" ] && [ -s "$PID_FILE" ]; then
|
||
SERVER_PID=$(cat "$PID_FILE")
|
||
if kill -0 "$SERVER_PID" 2>/dev/null; then
|
||
echo ""
|
||
echo "✅ 服务已启动,PID: $SERVER_PID"
|
||
break
|
||
fi
|
||
fi
|
||
echo -n "."
|
||
sleep 1
|
||
done
|
||
echo ""
|
||
|
||
# 检查状态
|
||
if [ -f "$PID_FILE" ]; then
|
||
SERVER_PID=$(cat "$PID_FILE")
|
||
echo ""
|
||
echo "服务器状态:"
|
||
echo "PID文件: $PID_FILE"
|
||
echo "主进程PID: $SERVER_PID"
|
||
|
||
# 检查进程
|
||
if ps -p "$SERVER_PID" > /dev/null; then
|
||
echo "进程状态: ✅ 运行中"
|
||
|
||
# 检查端口
|
||
sleep 2
|
||
if netstat -tulpn 2>/dev/null | grep ":$PORT " >/dev/null; then
|
||
echo "端口状态: ✅ $PORT 监听中"
|
||
else
|
||
echo "端口状态: ⚠️ $PORT 未监听"
|
||
fi
|
||
|
||
# 检查worker进程
|
||
WORKER_COUNT=$(ps -ef | grep "gunicorn.*worker" | grep -v grep | wc -l)
|
||
echo "工作进程: $WORKER_COUNT"
|
||
|
||
echo ""
|
||
echo "✅ 部署成功!"
|
||
echo "访问地址: http://localhost:$PORT"
|
||
echo "日志文件: $LOG_FILE"
|
||
echo "错误日志: $APP_DIR/error.log"
|
||
echo "访问日志: $APP_DIR/access.log"
|
||
else
|
||
echo "❌ 进程未运行"
|
||
echo "请查看日志文件: $LOG_FILE"
|
||
echo "最后10行日志:"
|
||
tail -10 "$LOG_FILE" 2>/dev/null || echo "无法读取日志文件"
|
||
fi
|
||
else
|
||
echo "❌ PID文件未创建,启动失败"
|
||
echo "请查看日志文件: $LOG_FILE"
|
||
echo "最后10行日志:"
|
||
tail -10 "$LOG_FILE" 2>/dev/null || echo "无法读取日志文件"
|
||
fi
|
||
|