Skip to content

panel: readiness-gate /api/health on Postgres (fix panel-roll 502s) - #21

Merged
pipozzz merged 1 commit into
mainfrom
feat/panel-readiness-gate
Oct 6, 2026
Merged

pipozzz merged 1 commit into
mainfrom
feat/panel-readiness-gate

Conversation

@pipozzz

@pipozzz pipozzz commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Problem

A panel self-roll drops the UI briefly (measured ~11s of 502 across one roll, over ~44s). Root cause: /api/health returned a static 200 the instant Next could answer an API route — long before the app can serve pages/tRPC, and even with Postgres down. The panel's canary promotes on this check (update { health_check = "checks" }), so it cut Traefik over to an alloc that 502'd on real requests.

Fix

/api/health now reports ready only once Postgres answers (SELECT 1, 2s cap under the 3s Nomad check timeout):

  • The canary is only promoted into an alloc that can actually serve DB-backed requests.
  • Closes the known roll failure mode where a new alloc comes up before Postgres accepts connections.
  • A ready latch keeps it green after the first success, so a steady-state DB blip can't flap the already-serving panel out of Traefik. Safe because the panel job has no check_restart — a failing check only affects routing/promotion, never kills the running alloc.

Scope

One file (apps/dokploy/pages/api/health.ts). First lever of the panel zero-downtime work; measure the next roll after this before deciding whether overlap + sticky sessions are also needed.

Validation

scripts/check.sh green (server build, 529 tests, app-tsc unchanged). Needs live measurement post-roll.

🤖 Generated with Claude Code

/api/health returned 200 immediately — the moment Next could answer an API
route — so the panel's canary (update{health_check="checks"}) promoted before
the app could serve pages/tRPC, and even with Postgres unreachable. Traefik cut
traffic to an alloc that 502'd on real requests → the panel-roll downtime
(measured ~11s of 502 across one roll).

Now it reports ready only once Postgres answers (SELECT 1, 2s cap under the 3s
check timeout), so the canary only promotes into a serving alloc — and the known
PG-connect roll failure mode can't promote a DB-less alloc either. A ready latch
keeps it green after first success so a steady-state DB blip can't flap the
running panel out of Traefik; safe because the panel job has no check_restart.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pipozzz
pipozzz merged commit e12ab9a into main Oct 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant