summaryrefslogtreecommitdiff
path: root/scripts/test-health-checks.sh
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-09-20 00:36:17 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-09-20 00:36:17 +0000
commit36a82d934366cc2ddbd92ee3885b1c547eeb8244 (patch)
tree06b92cd5b00145ebb2f3faacb9fb1bacccf5fb27 /scripts/test-health-checks.sh
parentc58f7519936dc547ee2aec5bfbb1e477356656d9 (diff)
Fold the DB-ping health check in; delete the watchdog that never ran
scripts/health-watchdog.sh was written after the 2026-08-04 incident, where a liveness stub stayed green for three days while every database-touching request path was wedged. Its header says "Meant to run from cron every few minutes". It was never scheduled — not in any unit, not in any crontab — so it has been dead code since August, offering coverage it did not provide. Its one real idea is worth keeping: /health pings the database and returns 503 when that fails, which the gateway route checks cannot see, because `/` answers 303 to the login page without going near the database. check_app_health now does that poll (two attempts, five seconds apart, so a single blip is not an outage), verify-deploy asserts it, and health-check recovers from it by restarting the main service — the action the old watchdog would have taken. The dead script is removed rather than left to imply cover. Tests now 11, including a stub server returning 503 to prove a listening-but- wedged app is caught. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'scripts/test-health-checks.sh')
-rwxr-xr-xscripts/test-health-checks.sh40
1 files changed, 40 insertions, 0 deletions
diff --git a/scripts/test-health-checks.sh b/scripts/test-health-checks.sh
index fbe9e47..fa59d8b 100755
--- a/scripts/test-health-checks.sh
+++ b/scripts/test-health-checks.sh
@@ -121,6 +121,46 @@ else
bad "subshell semantics" "array unexpectedly survived a subshell"
fi
+printf '=== check_app_health ===\n'
+
+# Unreachable app: must fail, not be mistaken for healthy.
+APP_HEALTH_URL="http://127.0.0.1:9/health"
+out=$(check_app_health); rc=$?
+if [ $rc -ne 0 ] && printf '%s' "$out" | grep -q "app health"; then
+ ok "catches an unreachable app health endpoint"
+else
+ bad "unreachable health endpoint" "rc=$rc out=$(printf '%s' "$out" | tr '\n' ' ')"
+fi
+
+# A 503 is what /health returns when the database is unreachable — the app is
+# listening and answering, so only this check can see it.
+python3 - "$tmp/hport" <<'PY2' &
+import http.server, socketserver, sys
+class H(http.server.BaseHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(503); self.end_headers()
+ self.wfile.write(b"db unreachable")
+ def log_message(self, *a): pass
+with socketserver.TCPServer(("127.0.0.1", 0), H) as s:
+ open(sys.argv[1], "w").write(str(s.server_address[1]))
+ s.serve_forever()
+PY2
+hpid=$!
+for _ in $(seq 1 50); do [ -s "$tmp/hport" ] && break; sleep 0.1; done
+hport=$(cat "$tmp/hport" 2>/dev/null || echo "")
+if [ -n "$hport" ]; then
+ APP_HEALTH_URL="http://127.0.0.1:${hport}/health"
+ out=$(check_app_health); rc=$?
+ if [ $rc -ne 0 ] && printf '%s' "$out" | grep -q "503"; then
+ ok "catches a listening app whose database ping fails (503)"
+ else
+ bad "503 db-ping detection" "rc=$rc out=$(printf '%s' "$out" | tr '\n' ' ')"
+ fi
+else
+ bad "503 db-ping detection" "could not start stub server"
+fi
+kill "$hpid" 2>/dev/null; wait "$hpid" 2>/dev/null
+
printf '=== check_build_stamp ===\n'
out=$(check_build_stamp "definitely-not-the-running-commit"); rc=$?