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:
yumoqing 2026-05-16 22:08:52 +08:00
parent 2e86b7a008
commit 53285aa17e
2 changed files with 183 additions and 0 deletions

104
start.sh Executable file
View 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
View 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 "========================================="