Skip to content

feat(health): M5-03 — /ready readiness probe, compose healthcheck gate#220

Merged
bihius merged 3 commits into
mainfrom
keen-poitras-3822ff
Jun 2, 2026
Merged

feat(health): M5-03 — /ready readiness probe, compose healthcheck gate#220
bihius merged 3 commits into
mainfrom
keen-poitras-3822ff

Conversation

@bihius
Copy link
Copy Markdown
Owner

@bihius bihius commented Jun 2, 2026

Summary

  • Adds GET /ready — a real readiness probe that checks DB connectivity (SELECT 1) and whether the runtime config volume is a writable directory. Returns 200 with per-check status when healthy, 503 with a detailed breakdown when any dependency is unavailable.
  • Keeps GET /health as a pure liveness probe (static 200, no dependencies checked).
  • Switches the Docker Compose backend healthcheck from /health/ready so the five dependent services (frontend, haproxy, coraza, log-shipper) only start once the backend can actually serve traffic.
  • Fixes a silent bug: GUARD_PROXY_RUNTIME_DIR in compose was never read by the Python settings layer (field is RUNTIME_GENERATED_CONFIG_ROOT). Renamed to match; value is unchanged.

What changed and why

File Change
src/backend/app/main.py New readiness_check endpoint; extends _HealthcheckAccessFilter to also suppress GET /ready poll noise; updated imports
deploy/docker/docker-compose.yml Healthcheck URL /health/ready; env var rename fix
tests/integration/test_health_router.py 7 new tests: liveness 200, readiness 200 (happy path), 503 on DB failure, 503 on missing config dir, 503 when both fail, auth-not-required for both
tests/unit/test_access_logging.py 2 new tests for the updated filter
README.architecture.md New "Health and Readiness Probes" section with endpoint table and response shape examples
README.md Access table updated with separate liveness/readiness rows

Response shape

// GET /ready → 200
{"status": "ready", "checks": {"database": {"status": "ok"}, "runtime_config": {"status": "ok"}}}

// GET /ready → 503 (one check failed)
{"status": "not ready", "checks": {"database": {"status": "ok"}, "runtime_config": {"status": "error", "detail": "/var/lib/guard-proxy/generated is not a writable directory"}}}

Test plan

  • uv run python -m pytest tests/unit/test_access_logging.py tests/integration/test_health_router.py -v — 12/12 passed
  • Full compose stack: make run → confirm backend reaches healthy state and all dependents start
  • Manual: curl -i localhost:8080/health (200), curl -i localhost:8080/ready (200)

Closes #128

… gate

- Add GET /ready that checks DB connectivity (SELECT 1) and runtime config
  volume writable; returns 200 {"status":"ready",...} or 503 with per-check
  breakdown so operators can tell which dependency is down
- Keep GET /health as a pure liveness probe (process-alive, no deps)
- Suppress GET /ready access-log noise in _HealthcheckAccessFilter
- Switch Docker Compose backend healthcheck from /health to /ready so the
  entire dependent stack (frontend, haproxy, coraza, log-shipper) only starts
  once the backend can actually serve real traffic
- Fix dead GUARD_PROXY_RUNTIME_DIR env var in compose → RUNTIME_GENERATED_CONFIG_ROOT
  (value unchanged; previous name was never read by the Python settings layer)
- 12 tests (7 integration + 2 unit new, 3 existing unit retained)

Closes #128

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 15:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a real readiness probe to the FastAPI backend and wires Docker Compose health checks to gate dependent services on actual backend readiness (DB + runtime config volume), while keeping /health as a lightweight liveness endpoint.

Changes:

  • Added GET /ready readiness probe (DB SELECT 1 + runtime generated config directory is writable) and updated access-log filtering to suppress probe noise.
  • Updated Compose backend healthcheck to call /ready and fixed the runtime config env var name to match the backend settings field.
  • Added integration/unit tests for the probes and logging filter; updated README docs to document both endpoints.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/backend/app/main.py Implements /ready readiness probe and suppresses access logs for /ready polling.
deploy/docker/docker-compose.yml Switches healthcheck endpoint to /ready and renames env var to RUNTIME_GENERATED_CONFIG_ROOT.
src/backend/tests/integration/test_health_router.py Adds integration coverage for /health and /ready success/failure scenarios.
src/backend/tests/unit/test_access_logging.py Extends unit coverage for access-log filter to include /ready.
README.architecture.md Documents liveness vs readiness probes, response shape, and Compose gating behaviour.
README.md Updates quickstart access table to list both probes.

Comment thread src/backend/app/main.py
Comment thread src/backend/app/main.py
bihius and others added 2 commits June 2, 2026 17:42
- Replace str(exc) in DB error detail with generic "database unavailable"
  message; log full exception at ERROR level instead to avoid leaking
  internal hostnames/credentials through the unauthenticated probe
- Add os.X_OK to the runtime config dir access check (W_OK alone doesn't
  guarantee files can be created inside a directory)
- Tighten test assertion to verify the generic detail string

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bihius bihius merged commit 470fbcc into main Jun 2, 2026
3 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.

M5-03 — Health and readiness probes

2 participants