122 lines
5.5 KiB
Bash
122 lines
5.5 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# 守护重启: main.py 被外部 kill / 异常退出后, 自动拉起(共享机上挡不住别人kill, 就让它自己回来)。
|
|
# 【带明确开关, 想关随时关, 不会和你抢】:
|
|
# 关闭原理 = 放一个"暂停标记文件" .guard_paused, 守护看到它就什么都不做。
|
|
#
|
|
# 用法:
|
|
# bash scripts/守护重启.sh install # 安装(每分钟检测一次, 没在跑就启动)
|
|
# bash scripts/守护重启.sh off # ★想停就用这个★ 暂停自动重启 + 停掉当前进程
|
|
# bash scripts/守护重启.sh on # 重新开启自动重启(下一分钟内会被拉起)
|
|
# bash scripts/守护重启.sh status # 看状态(装没装/开没开/在没在跑)
|
|
# bash scripts/守护重启.sh uninstall # 彻底卸载(删掉定时任务, 进程不动)
|
|
# bash scripts/守护重启.sh tick # (cron 内部调用, 别手动跑)
|
|
#
|
|
# 启动参数想改, 改下面 START= 这一行即可。
|
|
# =============================================================================
|
|
set -u
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
PAUSE="$ROOT/.guard_paused" # 这个文件存在 = 暂停自动重启
|
|
LOCK="$ROOT/.guard.lock"
|
|
GLOG="$ROOT/guard.log"
|
|
CRON_TAG="# ocr-guard" # crontab 里的标识, 用于增删去重
|
|
|
|
# ★ 启动命令(按之前调优建议; 想改并发/参数改这里) ★
|
|
# MODE=worker(默认): 常驻 worker 从 COS 认领任务; MODE=local: 旧的本地 text2 模式。
|
|
# nice -n 15: 让 co-located 的 OCR 服务优先抢 CPU; max-tasks-per-child 20: 本机内存偏紧
|
|
# (44G可用/184G总量), 定期回收worker释放常驻内存; 3.11回收有缩水风险(见CLAUDE.md), 但20这个
|
|
# 量级配合 --mem-guard-gb 观察下来风险可控, 内存不紧的机器可以改回0(不回收)。
|
|
if [ -z "${MODE:-}" ]; then
|
|
_src="$(python -c "from config.config_utils import config; print((config.get_dispatch_config() or {}).get('source','cos'))" 2>/dev/null || echo cos)"
|
|
[ "$_src" = "local" ] && MODE="local" || MODE="worker"
|
|
fi
|
|
MODE="${MODE:-worker}"
|
|
if [ "$MODE" = "worker" ]; then
|
|
START='nice -n 15 python run_worker.py --max-workers 30 --max-tasks-per-child 20 --mem-guard-gb 30 --executor process'
|
|
PROC_PAT='python .*run_worker\.py'
|
|
else
|
|
START='nice -n 15 python main.py --source-list ./text2 --max-workers 30 --max-tasks-per-child 20 --mem-guard-gb 30 --executor process'
|
|
PROC_PAT='python .*main\.py'
|
|
fi
|
|
|
|
# 判断父进程是否在跑(forkserver worker 命令行不含入口文件名, 不会误判)
|
|
running() {
|
|
pgrep -af "$PROC_PAT" 2>/dev/null | grep -v 'multiprocessing' | grep -v 'grep' >/dev/null 2>&1
|
|
}
|
|
|
|
# app.log 轮转: 进程可能正在往它里面 >> 追加写, 不能直接 mv(会导致进程还在写旧inode, 新文件
|
|
# 看起来永远是空的) —— 用 copytruncate: 先 cp 一份出去, 再原地截断; O_APPEND 的fd是按"当前
|
|
# 文件大小"找写入位置的, 原地截断后进程会自动从offset 0继续写这个(同一个)文件, 不受影响。
|
|
_rotate_applog() {
|
|
local f="$ROOT/app.log" maxmb=200
|
|
[ -f "$f" ] || return 0
|
|
local sz_mb=$(( $(stat -c%s "$f" 2>/dev/null || echo 0) / 1024 / 1024 ))
|
|
if [ "$sz_mb" -ge "$maxmb" ]; then
|
|
local ts; ts="$(date +%Y%m%d_%H%M%S)"
|
|
cp "$f" "${f}.${ts}" 2>/dev/null && : > "$f" \
|
|
&& echo "$(date '+%F %T') [日志轮转] app.log(${sz_mb}M) → app.log.${ts}, 原地清空续写" >> "$GLOG"
|
|
ls -t "${f}".[0-9]* 2>/dev/null | tail -n +6 | xargs -r rm -f # 只留最近5份
|
|
fi
|
|
}
|
|
|
|
case "${1:-status}" in
|
|
install)
|
|
( crontab -l 2>/dev/null | grep -vF "$CRON_TAG"
|
|
echo "* * * * * cd $ROOT && bash scripts/守护重启.sh tick $CRON_TAG" ) | crontab -
|
|
rm -f "$PAUSE"
|
|
echo "✓ 守护已安装(每分钟检测), 自动重启: 开启"
|
|
echo " 想停: bash scripts/守护重启.sh off"
|
|
;;
|
|
|
|
uninstall)
|
|
crontab -l 2>/dev/null | grep -vF "$CRON_TAG" | crontab -
|
|
echo "✓ 已卸载守护定时任务(不再自动重启)。当前进程未动。"
|
|
echo " 如要同时停进程: bash scripts/stop.sh -y"
|
|
;;
|
|
|
|
off)
|
|
touch "$PAUSE"
|
|
echo "✓ 已暂停自动重启(标记 $PAUSE)。正在停止当前进程..."
|
|
bash "$ROOT/scripts/stop.sh" -y
|
|
echo "✓ 已停止, 且守护不会再把它拉起。恢复运行: bash scripts/守护重启.sh on"
|
|
;;
|
|
|
|
on)
|
|
rm -f "$PAUSE"
|
|
echo "✓ 自动重启已开启。若当前没在跑, 一分钟内会被拉起。"
|
|
;;
|
|
|
|
tick)
|
|
# 暂停中 → 什么都不做(这就是 off 之所以能稳关掉的原因)
|
|
[ -f "$PAUSE" ] && exit 0
|
|
# 防并发: 同一时刻只允许一个 tick 启动
|
|
exec 9>"$LOCK"
|
|
flock -n 9 || exit 0
|
|
_rotate_applog # 每分钟顺带检查一次, 跟要不要重启无关(常驻不重启时全靠这个兜底)
|
|
running && exit 0
|
|
echo "$(date '+%F %T') 检测到未运行 → 启动" >> "$GLOG"
|
|
setsid nohup $START >> "$ROOT/app.log" 2>&1 &
|
|
;;
|
|
|
|
status)
|
|
echo "项目目录: $ROOT"
|
|
if crontab -l 2>/dev/null | grep -qF "$CRON_TAG"; then
|
|
echo "守护定时任务: ✓ 已安装(每分钟检测)"
|
|
else
|
|
echo "守护定时任务: ✗ 未安装"
|
|
fi
|
|
if [ -f "$PAUSE" ]; then
|
|
echo "自动重启: ⏸ 已暂停 (.guard_paused 存在 → 不会拉起)"
|
|
else
|
|
echo "自动重启: ▶ 开启"
|
|
fi
|
|
if running; then echo "main.py: 运行中"; else echo "main.py: 未运行"; fi
|
|
;;
|
|
|
|
*)
|
|
echo "用法: install | on | off | uninstall | status | tick"
|
|
;;
|
|
esac
|