Repository navigation
fix(health): readiness probe returns 503 when the database is down - #602
Merged
Merged
Conversation
readiness() caught the Terminus ServiceUnavailableException and returned a plain object, which NestJS serialized as HTTP 200 - so a pod that lost Postgres stayed Ready, kept taking traffic, and a maxUnavailable=0 rollout could replace both pods into a broken DB config successfully. Let the exception propagate so the probe sees the 503, and gate readiness on the database only: a Matrix outage degrades chat, not the API, and must not pull every api pod out of the Service endpoints (/health/matrix still carries that signal). Spec: the disconnected case now expects propagation instead of an error body, plus HTTP-level tests through the real Terminus pipeline - the old behavior (200 with the DB ping failing) was observed failing before the fix. Refs: om-ep1ej
The app registers GlobalExceptionFilter via APP_FILTER
(interceptors.module.ts), so in production it catches the propagated
ServiceUnavailableException, keeps the 503, and rewrites the body to
{statusCode, message, path, timestamp}. Mirror that in the HTTP-level
spec so the asserted response is the one the probes actually see.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
readiness()wrapped the Terminus check in a try/catch and returned a plain object on failure, which NestJS serializes as HTTP 200. So a pod that can't reach Postgres passes its readiness probe:maxUnavailable=0rolling update into a broken DB config replaces both pods and completes "successfully"The old behavior was observed before the fix: with the database ping failing,
GET /health/readinessanswered 200 through the real Terminus pipeline (the new HTTP-level spec, run pre-fix, failed withExpected: 503, Received: 200).Fix
ServiceUnavailableExceptionpropagate — the 503 is how the probe reports "not ready"./health/matrixstill carries that signal.livenessis unchanged (its always-OK behavior is deliberate).The spec test asserting the error body (
should return status error when database is disconnected) encoded the old behavior and is flipped deliberately: it now asserts propagation. New HTTP-level tests cover 503 on DB-down, 200 healthy, and matrix staying out of readiness.Consumers checked
GlobalExceptionFilter(registered viaAPP_FILTERinInterceptorsModule) catches the propagated exception, keeps the 503 (getStatus()for anyHttpException), and rewrites the body to{statusCode, message, path, timestamp}— the HTTP spec runs through the filter so it asserts the response the probes actually see. The k8s probes, Prometheus blackbox probe (http_2xxmodule), and ingress health check all read the status code; nothing parses the old error body.test/kubernetes/kubernetes.e2e-spec.tsruns against a healthy environment and still passes.One side effect to be aware of: each failing readiness hit now also increments
unhandled_exceptions_totaland error-logs via the filter — a DB-down pod gets loud, which seems right for this failure.Refs: om-ep1ej