feat: multi-process worker scaling for Sage web app
- Refactor start.sh to launch multiple worker processes based on CPU core count - Assign dynamic ports to each worker (base_port + offset) - Update stop.sh to gracefully handle and kill multiple worker PIDs - Implement PID file management for multi-process tracking
This commit is contained in:
parent
2e86b7a008
commit
53285aa17e
104
start.sh
Executable file
104
start.sh
Executable file
@ -0,0 +1,104 @@
|
||||
#!/bin/bash
|
||||
# Sage Web Application Start Script
|
||||
# Multi-process support based on CPU cores
|
||||
|
||||
set -e
|
||||
|
||||
# 切换到脚本所在目录
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# 配置
|
||||
WORKDIR="$(pwd)"
|
||||
PYTHON="./py3/bin/python"
|
||||
APP_ENTRY="app/sage.py"
|
||||
PIDFILE="$WORKDIR/sage.pid"
|
||||
LOGDIR="$WORKDIR/logs"
|
||||
|
||||
# 确保logs目录存在
|
||||
mkdir -p "$LOGDIR"
|
||||
|
||||
# 检查Python是否存在
|
||||
if [ ! -f "$PYTHON" ]; then
|
||||
echo "错误: 找不到Python解释器 $PYTHON"
|
||||
echo "请确保已安装虚拟环境: ./py3/bin/python"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查应用入口文件是否存在
|
||||
if [ ! -f "$APP_ENTRY" ]; then
|
||||
echo "错误: 找不到应用入口文件 $APP_ENTRY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查Redis是否运行(session存储依赖)
|
||||
if command -v redis-cli &> /dev/null; then
|
||||
if ! redis-cli ping &> /dev/null; then
|
||||
echo "Redis未运行,正在启动Redis..."
|
||||
redis-server --daemonize yes
|
||||
sleep 1
|
||||
if redis-cli ping &> /dev/null; then
|
||||
echo "Redis启动成功"
|
||||
else
|
||||
echo "警告: Redis启动失败,登录功能可能无法正常工作"
|
||||
fi
|
||||
else
|
||||
echo "Redis运行正常"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "========================================="
|
||||
echo "启动 Sage Web Application"
|
||||
echo "工作目录: $WORKDIR"
|
||||
echo "Python: $PYTHON"
|
||||
echo "========================================="
|
||||
|
||||
# 获取 CPU 核心数,决定启动多少 Worker
|
||||
WORKERS=$(nproc)
|
||||
echo "检测到 ${WORKERS} 个 CPU 核心,准备启动 ${WORKERS} 个工作进程..."
|
||||
|
||||
# 获取基础端口
|
||||
BASE_PORT=9180
|
||||
if command -v python3 &> /dev/null; then
|
||||
BASE_PORT=$($PYTHON -c "
|
||||
import json
|
||||
try:
|
||||
with open('$WORKDIR/conf/config.json') as f:
|
||||
config = json.load(f)
|
||||
print(config.get('website', {}).get('port', 9180))
|
||||
except Exception as e:
|
||||
print(9180)
|
||||
" 2>/dev/null || echo 9180)
|
||||
fi
|
||||
|
||||
# 清空 PID 文件
|
||||
> "$PIDFILE"
|
||||
|
||||
# 循环启动 Worker
|
||||
for (( i=0; i<WORKERS; i++ ))
|
||||
do
|
||||
PORT=$((BASE_PORT + i))
|
||||
LOGFILE="$LOGDIR/sage_worker_${i}.log"
|
||||
|
||||
echo ">>> 启动 Worker $((i+1))/${WORKERS} on port $PORT ..."
|
||||
|
||||
# 启动服务
|
||||
nohup $PYTHON $APP_ENTRY --workdir "$WORKDIR" --port $PORT > "$LOGFILE" 2>&1 &
|
||||
APP_PID=$!
|
||||
|
||||
# 保存 PID
|
||||
echo "$APP_PID" >> "$PIDFILE"
|
||||
|
||||
# 短暂等待以检查是否立即崩溃
|
||||
sleep 1
|
||||
if kill -0 $APP_PID 2>/dev/null; then
|
||||
echo " -> Worker PID: $APP_PID (成功)"
|
||||
else
|
||||
echo " -> 错误: Worker 启动失败,请查看 $LOGFILE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "========================================="
|
||||
echo "所有服务已启动"
|
||||
echo "PID 文件: $PIDFILE"
|
||||
echo "访问地址: http://localhost:${BASE_PORT} (以及其他 ${WORKERS} 个端口)"
|
||||
echo "========================================="
|
||||
79
stop.sh
Executable file
79
stop.sh
Executable file
@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
# Sage Web Application Stop Script
|
||||
# Supports multi-process setup
|
||||
|
||||
set -e
|
||||
|
||||
# 切换到脚本所在目录
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
WORKDIR="$(pwd)"
|
||||
PIDFILE="$WORKDIR/sage.pid"
|
||||
|
||||
echo "========================================="
|
||||
echo "停止 Sage Web Application"
|
||||
echo "========================================="
|
||||
|
||||
STOPPED_PIDS=""
|
||||
|
||||
# 1. 尝试从 PID 文件停止
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
echo "读取 PID 文件..."
|
||||
while read -r APP_PID; do
|
||||
# 跳过空行
|
||||
if [ -z "$APP_PID" ]; then continue; fi
|
||||
|
||||
if kill -0 "$APP_PID" 2>/dev/null; then
|
||||
echo "正在停止 Worker (PID: $APP_PID) ..."
|
||||
kill "$APP_PID" 2>/dev/null || true
|
||||
STOPPED_PIDS="$STOPPED_PIDS $APP_PID"
|
||||
else
|
||||
echo "Worker (PID: $APP_PID) 已停止"
|
||||
fi
|
||||
done < "$PIDFILE"
|
||||
|
||||
# 等待进程结束
|
||||
WAIT_COUNT=0
|
||||
while [ $WAIT_COUNT -lt 10 ]; do
|
||||
ALL_STOPPED=true
|
||||
for PID in $STOPPED_PIDS; do
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
ALL_STOPPED=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if $ALL_STOPPED; then
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
WAIT_COUNT=$((WAIT_COUNT + 1))
|
||||
echo "等待服务关闭... ($WAIT_COUNT/10)"
|
||||
done
|
||||
|
||||
# 强制杀死未退出的
|
||||
for PID in $STOPPED_PIDS; do
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
echo "强制停止进程: $PID"
|
||||
kill -9 "$PID" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 2. 兜底清理 (通过进程名查找,防止 PID 文件丢失)
|
||||
# 注意:这里匹配 app/sage.py
|
||||
PIDS=$(ps aux | grep "[a]pp/sage.py" | awk '{print $2}' || true)
|
||||
if [ -n "$PIDS" ]; then
|
||||
echo "发现残留进程,强制清理..."
|
||||
for PID in $PIDS; do
|
||||
kill -9 "$PID" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
# 清理 PID 文件
|
||||
rm -f "$PIDFILE"
|
||||
|
||||
echo "========================================="
|
||||
echo "服务已停止"
|
||||
echo "========================================="
|
||||
Loading…
x
Reference in New Issue
Block a user