diff --git a/deploy/push.sh b/deploy/push.sh index bce6a17..a4d8bc7 100755 --- a/deploy/push.sh +++ b/deploy/push.sh @@ -17,6 +17,9 @@ set -e HOST="${1:-ericwyuan@192.168.50.64}" PORT="${2:-2222}" +# Needed for the sudo restart below. Prompted for rather than stored, and only +# used over the already-authenticated ssh master connection. +PASS="${NAS_PASSWORD:-}" REPO="$(cd "$(dirname "$0")/.." && pwd)" CTL="$(mktemp -u /tmp/garmin-deploy-XXXXXX)" @@ -28,6 +31,13 @@ trap cleanup EXIT echo "==> connecting to $HOST:$PORT (password prompt follows, once)" ssh -M -S "$CTL" -fN -p "$PORT" -o ControlPersist=300 "$HOST" +if [ -z "$PASS" ]; then + # Same password as the ssh login; asked for separately because ssh consumed + # the first one itself and sudo on the far side needs it on stdin. + printf 'sudo password for %s (needed to restart the root-owned service): ' "$HOST" >&2 + stty -echo 2>/dev/null; read PASS; stty echo 2>/dev/null; echo >&2 +fi + # The app dir has moved before; find it rather than assume it. APP=$(sh_ 'for d in ~/apps/garmin-health-lab /volume1/web/garmin-health-lab; do [ -d "$d/backend" ] && { echo "$d"; break; }; done') @@ -60,10 +70,30 @@ fi sh_ "rm -rf '$STATIC' && mkdir -p '$STATIC'" $TAR -C "$REPO/client/build" . | sh_ "tar xzf - -C '$STATIC'" -echo "==> restart" -sh_ "sh '$APP/deploy/stop.sh' >/dev/null 2>&1; sleep 2; sh '$APP/deploy/start.sh'" +# The service is started at boot as root (DSM Task Scheduler -> S99garmin.sh), +# so logs/error.log and logs/access.log are root-owned. Restarting as +# ericwyuan therefore fails instantly — gunicorn cannot open its own error log +# — and this went unnoticed for a whole deploy: stop.sh could not kill a root +# process either, so the OLD master kept serving :8124, start.sh's health +# check saw a 200 and reported "started", and the new code was never loaded. +# Hence sudo, matching how the service actually runs. +SUDO="echo '$PASS' | sudo -S" +echo "==> restart (sudo: the service runs as root, started at boot)" +BEFORE=$(sh_ "pgrep -f '$APP/backend/.venv/bin/gunicorn' | tr '\n' ',' " || true) +sh_ "cd '$APP' && $SUDO sh deploy/stop.sh >/dev/null 2>&1; sleep 3; $SUDO sh deploy/start.sh" \ + || { echo "restart failed" >&2; exit 1; } echo "==> health" sh_ "curl -sf -m 5 -o /dev/null -w 'local api: %{http_code}\n' \ http://127.0.0.1:8124/api/health/status" || echo "local api: unreachable" + +# A 200 alone proves nothing: it is exactly what a surviving old master +# returns. The master pid must have changed for the new code to be loaded. +AFTER=$(sh_ "pgrep -f '$APP/backend/.venv/bin/gunicorn' | tr '\n' ',' " || true) +if [ -n "$BEFORE" ] && [ "$BEFORE" = "$AFTER" ]; then + echo "the gunicorn pids did not change ($AFTER) - the old process is still" >&2 + echo "serving and your changes are NOT live. Check $APP/logs/error.log." >&2 + exit 1 +fi +echo "==> gunicorn restarted: $BEFORE -> $AFTER" echo "done. The public URL takes a few seconds longer (frp reconnecting)."