From afeb0902a14b5720fb4d380fdff3c221257141ff Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Sat, 8 Aug 2026 21:23:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BF=9B=E7=A8=8B=E5=AE=88=E6=8A=A4=20?= =?UTF-8?q?supervise.sh=EF=BC=8C=E5=B4=A9=E6=BA=83=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E9=87=8D=E5=90=AF=EF=BC=9BDEPLOY=20=E8=A1=A5=20docker=20health?= =?UTF-8?q?check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/supervise.sh:web_server 崩溃自动重启,带 2s 退避和 300s 窗口内重启上限(10次)防死循环 - doc/DEPLOY.md 补充通用守护用法 + python-app 容器 healthcheck 配置 --- doc/DEPLOY.md | 25 ++++++++++++++++++++ scripts/supervise.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100755 scripts/supervise.sh diff --git a/doc/DEPLOY.md b/doc/DEPLOY.md index bb3cc3a..966dfed 100644 --- a/doc/DEPLOY.md +++ b/doc/DEPLOY.md @@ -149,6 +149,31 @@ RestartSec=10 WantedBy=multi-user.target ``` +**通用脚本(Linux/macOS,无需 systemd)**: + +项目自带 `scripts/supervise.sh`:web_server 崩溃自动重启、带退避和重启上限(防崩溃死循环)。 + +```bash +# 用 venv 的 python 守护 +PYTHON=./.venv/bin/python bash scripts/supervise.sh +``` + +> 进程守护只保证服务重启,不恢复已运行的任务(worker 状态在内存)。崩溃后残留的设备占用需用"强制释放占用"清理(或启动时的提示)。 + +**Docker(生产 python-app 容器)**: + +docker-compose 已配置 `restart: unless-stopped`,web_server 进程退出 → 容器退出 → Docker 自动重启。建议再加健康检查,让编排感知服务存活: + +```yaml +# docker-compose.yaml 的 python-app 服务下添加 +healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:18050/api/health', timeout=3)"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s +``` + ### 3.2 反向代理(可选) 如需 HTTPS 或 80 端口,用 Nginx 反向代理: diff --git a/scripts/supervise.sh b/scripts/supervise.sh new file mode 100755 index 0000000..d16835d --- /dev/null +++ b/scripts/supervise.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# web_server.py 进程守护脚本:崩溃自动重启,带退避和重启上限。 +# +# 用法: +# bash scripts/supervise.sh # 用 python3 启动 +# PYTHON=./.venv/bin/python bash scripts/supervise.sh # 指定 Python(venv) +# +# 行为: +# - web_server 崩溃(非 0/130 退出码)→ 等待 BACKOFF_MIN 秒自动重启 +# - 重启窗口(RESTART_WINDOW 秒)内超过 MAX_RESTARTS 次 → 停止(防崩溃死循环) +# - 正常退出(Ctrl+C=130 或 code=0)→ 守护结束 +# - 日志写到 logs/supervise.log +# +# 生产无人值守建议配合 Docker 的 restart: unless-stopped 或 systemd 一起用。 + +cd "$(dirname "$0")/.." +PYTHON="${PYTHON:-python3}" +mkdir -p logs + +MAX_RESTARTS="${MAX_RESTARTS:-10}" # 窗口内最大重启次数 +RESTART_WINDOW="${RESTART_WINDOW:-300}" # 重启窗口(秒) +BACKOFF_MIN="${BACKOFF_MIN:-2}" # 重启前等待(秒) + +restarts=0 +window_start=$(date +%s) + +echo "[$(date '+%F %T')] 进程守护启动,python=$PYTHON" +while true; do + echo "[$(date '+%F %T')] 启动 web_server.py..." + "$PYTHON" web_server.py >> logs/supervise.log 2>&1 + code=$? + echo "[$(date '+%F %T')] web_server 退出,code=$code" + + # 0 = 正常结束;130 = Ctrl+C(SIGINT)→ 手动停止,守护结束 + if [ "$code" -eq 0 ] || [ "$code" -eq 130 ]; then + echo "[$(date '+%F %T')] 正常退出,守护进程结束" + break + fi + + # 滑动窗口计数 + now=$(date +%s) + if [ $((now - window_start)) -gt "$RESTART_WINDOW" ]; then + window_start=$now + restarts=0 + fi + restarts=$((restarts + 1)) + if [ "$restarts" -gt "$MAX_RESTARTS" ]; then + echo "[$(date '+%F %T')] ${RESTART_WINDOW}s 内崩溃超过 ${MAX_RESTARTS} 次,停止守护(可能配置/环境问题)" + break + fi + + echo "[$(date '+%F %T')] ${BACKOFF_MIN}s 后重启 (窗口内第 ${restarts} 次)" + sleep "$BACKOFF_MIN" +done