From 283d530f824b3819ee20422b82701dd462392949 Mon Sep 17 00:00:00 2001 From: ericwyuan Date: Mon, 24 Aug 2026 04:23:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(deploy):=20=E5=90=AF=E5=8A=A8=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E7=AD=89=E7=AB=AF=E5=8F=A3=E7=9C=9F=E6=AD=A3=E9=87=8A?= =?UTF-8?q?=E6=94=BE=EF=BC=8C=E5=B9=B6=E7=A1=AE=E8=AE=A4=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=8F=AF=E7=94=A8=E5=90=8E=E6=89=8D=E6=8A=A5=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一次部署里旧 worker 没随 master 退出,一直占着 8123。新 master 启动、 打印 started、然后什么都不服务——日志每一行看起来都正常,站点却是挂的。 - stop.sh 等进程真正退出,超时后 -9 - start.sh 停完等端口释放,起来后 curl 健康检查通过才算成功,否则返回非零 Co-Authored-By: Claude Haiku 4.5 --- deploy/start.sh | 47 +++++++++++++++++++++++++++++++++++++++++++++++ deploy/stop.sh | 19 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100755 deploy/start.sh create mode 100755 deploy/stop.sh diff --git a/deploy/start.sh b/deploy/start.sh new file mode 100755 index 0000000..4fe2a61 --- /dev/null +++ b/deploy/start.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# Start Garmin Health Lab. Safe to run repeatedly: an already-running +# instance is stopped first. Intended for DSM Task Scheduler (boot-up). +APP="$(cd "$(dirname "$0")" && pwd)" +cd "$APP/backend" || exit 1 + +GUNICORN="$APP/backend/.venv/bin/gunicorn" + +# Stop whatever is already running, then WAIT for the port to actually be +# free. Killing only the pid in app.pid left orphaned workers holding :8123; +# the new master then started, reported success, and served nothing — the +# site was down while every log line looked normal. +"$APP/stop.sh" >/dev/null 2>&1 +i=0 +while [ $i -lt 20 ]; do + pgrep -f "$GUNICORN" >/dev/null 2>&1 || break + sleep 1 + i=$((i + 1)) +done +pkill -9 -f "$GUNICORN" 2>/dev/null +sleep 1 + +mkdir -p "$APP/logs" +# --timeout 300: an AI generation against the reasoning model can run for +# minutes, and gunicorn kills a worker that looks stuck before then. +nohup "$GUNICORN" \ + --workers 2 --threads 4 --timeout 300 \ + --bind 0.0.0.0:8123 \ + --access-logfile "$APP/logs/access.log" \ + --error-logfile "$APP/logs/error.log" \ + wsgi:app > "$APP/logs/stdout.log" 2>&1 & + +echo $! > "$APP/app.pid" + +# Confirm it is actually serving rather than just running. +i=0 +while [ $i -lt 25 ]; do + if curl -sf -m 2 -o /dev/null http://127.0.0.1:8123/api/health/status; then + echo "started pid $(cat "$APP/app.pid") on :8123" + exit 0 + fi + sleep 1 + i=$((i + 1)) +done + +echo "FAILED to serve on :8123 — see $APP/logs/error.log" >&2 +exit 1 diff --git a/deploy/stop.sh b/deploy/stop.sh new file mode 100755 index 0000000..d6c95da --- /dev/null +++ b/deploy/stop.sh @@ -0,0 +1,19 @@ +#!/bin/sh +APP="$(cd "$(dirname "$0")" && pwd)" +GUNICORN="$APP/backend/.venv/bin/gunicorn" + +if [ -f "$APP/app.pid" ]; then + kill "$(cat "$APP/app.pid")" 2>/dev/null && echo "stopped $(cat "$APP/app.pid")" + rm -f "$APP/app.pid" +fi + +# The master's workers do not always go with it, and a surviving worker keeps +# :8123 bound — which looks exactly like a healthy start that serves nothing. +i=0 +while [ $i -lt 15 ]; do + pgrep -f "$GUNICORN" >/dev/null 2>&1 || exit 0 + sleep 1 + i=$((i + 1)) +done +pkill -9 -f "$GUNICORN" 2>/dev/null +echo "force-stopped leftover workers"