feat: add container health and readiness checks #295

Merged
erik merged 1 commit from feat/task-83e123d4-health-readiness into main 2026-10-04 22:54:01 -05:00
Owner

Summary

  • Preserve existing /health and /api/v1/health JSON contracts as lightweight liveness; bypass setup/database lookups for probes.
  • Add /ready with stable JSON/version/database pass-or-fail, HTTP 200/503 and Cache-Control: no-store. Read migration requirements once and query applied IDs without DDL, migration execution or implicit DB initialization.
  • Required startup database/migration failures still stop the process before listening. Existing enabled-feature validation remains; optional disabled/external services are not polled or made readiness blockers. Readiness is independent of first-run owner onboarding.
  • Runtime Docker HEALTHCHECK invokes a small native Node script: configured host/port, 3s request deadline, redirects rejected, HTTP 200 and status ready required. No diagnostic dependency or TypeScript loader.
  • Generated deployment guidance uses /ready for rollout/traffic acceptance and /health for liveness; documents timing, startup failures, optional services, setup semantics and Docker restart behavior.
  • Add 19 focused unit cases: six Hono/readiness cases, twelve native-probe/static-Docker cases, one startup migration-failure case. Existing template archive regression verifies the new runtime script and readiness source ship.

Verification

  • Original five route cases failed before implementation: health depended on closed DB/setup lookup, no readiness signal, uninitialized/pending DB could not return stable JSON. Added no-implicit-init regression also failed before its fix.
  • ./scripts/pre-pr.sh passed generated CSS, formatting, lint, types and all 1,133 local tests (533 CLI, 550 site, 50 package tests).
  • npm run test:ci passed (527 CLI, 471 site); git diff --check passed.
  • Built the standalone site Docker image locally with release/version metadata. Verified actual runtime HEALTHCHECK declaration and Node script.
  • Local containers: initialized site became healthy/ready without owner setup or optional services; a temporary SQLite exclusive lock produced /health=200, /ready=503 with stable not_ready JSON, Docker unhealthy and native probe nonzero; releasing the lock restored readiness and Docker healthy.
  • Invalid required DB path caused startup to exit 1 and the container never reported ready/healthy.
  • Containers used isolated anonymous volumes, no published host ports and no real secrets; removed containers and their temporary volumes afterward. Probe timing overrides accelerated local verification only; image defaults remain interval 30s, timeout 5s, start-period 10s, retries 3.
  • Evidence: /tmp/slugkit-readiness-pre-pr.log, /tmp/slugkit-readiness-unit-ci.log, /tmp/slugkit-readiness-docker-build.log and /tmp/slugkit-readiness-containers.log; one-off local verifier /tmp/slugkit-verify-readiness-containers.sh.

No dependency or workflow changes. Native-script tests mock fetch/process and never start servers/containers. Actual container verification is LOCAL ONLY: NEVER integration/container tests or runtime provisioning in CI or release workflows.

Task: #task-83e123d4

Awaiting CI, independent review and explicit human merge approval.

## Summary - Preserve existing /health and /api/v1/health JSON contracts as lightweight liveness; bypass setup/database lookups for probes. - Add /ready with stable JSON/version/database pass-or-fail, HTTP 200/503 and Cache-Control: no-store. Read migration requirements once and query applied IDs without DDL, migration execution or implicit DB initialization. - Required startup database/migration failures still stop the process before listening. Existing enabled-feature validation remains; optional disabled/external services are not polled or made readiness blockers. Readiness is independent of first-run owner onboarding. - Runtime Docker HEALTHCHECK invokes a small native Node script: configured host/port, 3s request deadline, redirects rejected, HTTP 200 and status ready required. No diagnostic dependency or TypeScript loader. - Generated deployment guidance uses /ready for rollout/traffic acceptance and /health for liveness; documents timing, startup failures, optional services, setup semantics and Docker restart behavior. - Add 19 focused unit cases: six Hono/readiness cases, twelve native-probe/static-Docker cases, one startup migration-failure case. Existing template archive regression verifies the new runtime script and readiness source ship. ## Verification - Original five route cases failed before implementation: health depended on closed DB/setup lookup, no readiness signal, uninitialized/pending DB could not return stable JSON. Added no-implicit-init regression also failed before its fix. - ./scripts/pre-pr.sh passed generated CSS, formatting, lint, types and all 1,133 local tests (533 CLI, 550 site, 50 package tests). - npm run test:ci passed (527 CLI, 471 site); git diff --check passed. - Built the standalone site Docker image locally with release/version metadata. Verified actual runtime HEALTHCHECK declaration and Node script. - Local containers: initialized site became healthy/ready without owner setup or optional services; a temporary SQLite exclusive lock produced /health=200, /ready=503 with stable not_ready JSON, Docker unhealthy and native probe nonzero; releasing the lock restored readiness and Docker healthy. - Invalid required DB path caused startup to exit 1 and the container never reported ready/healthy. - Containers used isolated anonymous volumes, no published host ports and no real secrets; removed containers and their temporary volumes afterward. Probe timing overrides accelerated local verification only; image defaults remain interval 30s, timeout 5s, start-period 10s, retries 3. - Evidence: /tmp/slugkit-readiness-pre-pr.log, /tmp/slugkit-readiness-unit-ci.log, /tmp/slugkit-readiness-docker-build.log and /tmp/slugkit-readiness-containers.log; one-off local verifier /tmp/slugkit-verify-readiness-containers.sh. No dependency or workflow changes. Native-script tests mock fetch/process and never start servers/containers. Actual container verification is LOCAL ONLY: NEVER integration/container tests or runtime provisioning in CI or release workflows. Task: #task-83e123d4 Awaiting CI, independent review and explicit human merge approval.
feat: add container health and database readiness signals
All checks were successful
CI / build-lint-test (pull_request) Successful in 57s
83487f9173
Keep liveness independent of setup/database state, expose read-only migration readiness, and probe it with native Node in the runtime image. Document rollout semantics and verify healthy, unavailable database, recovery and failed initialization locally without adding container tests to CI.

Task: #task-83e123d4
Author
Owner

Independent PR review

  • PR: #295 (83487f91730ceb67caaf070c106fe09892217827), open
  • Task: task-83e123d4
  • Result: approved

Summary

The diff adds a scoped readiness signal and runtime Docker health check without changing the existing /health or /api/v1/health liveness contracts. Readiness is database/migration based, read-only, independent of owner setup, and returns stable ready/not_ready JSON with 200/503 and Cache-Control: no-store. The native Node healthcheck script uses only runtime-available Node globals and targets /ready.

Acceptance criteria

  • Runtime image declares a working Docker health check: template/site/Dockerfile copies scripts/healthcheck.mjs and declares HEALTHCHECK ... CMD ["node", "scripts/healthcheck.mjs"]; unit/static and local container evidence cover it.
  • A healthy initialized site becomes ready: /ready returns 200 with status: "ready" and checks.database: "pass" for initialized DBs, including before owner setup.
  • A site that cannot initialize a required dependency does not report ready: startup migration failures throw before serving; closed, missing/unmigrated, pending, locked, or unavailable DB cases return/not-report ready as expected.
  • Liveness and readiness endpoints have documented, tested semantics: README documents /health, /api/v1/health, and /ready; focused route tests cover liveness, readiness, setup-gate bypass, status codes, JSON, and no-store.
  • Optional disabled services do not make the site unready: readiness only checks the required database and does not contact fetch/S3/SMTP/remote peers; disabled ActivityPub/external-service test covers this.
  • Container-level verification covers healthy and unhealthy states: supplied local-only container verifier/logs show healthy initialized, database-locked unhealthy/not_ready, recovery, and failed required DB initialization.
  • Example deployment guidance uses the readiness signal for rollout checks: README instructs deployment rollouts to require node scripts/healthcheck.mjs/Docker health and route liveness to /health, readiness to /ready.

Quality and security

  • Scope is aligned with the approved liveness/readiness, native Docker healthcheck, docs, and local-only container verification; no dependency, workflow, CI, or lint-config changes are present.
  • Readiness uses only SELECT id FROM schema_migrations; it does not open/create databases, run migrations, mutate schema, expose DB paths, credentials, or exception details.
  • Existing startup fail-fast database initialization remains before HTTP bind; enabled-feature startup validation is not weakened.
  • Test coverage is focused: new route/readiness cases, native script/static Docker cases using mocked fetch/process, startup migration failure, and template archive shipping regression.
  • Reviewed evidence: red logs for preimplementation failures, pre-PR/full local and unit-CI logs, Docker build log, and local-only container verification log/script.

Blocking issues

  • None.

Warnings

  • None.

Final verdict

Approved. Awaiting explicit human merge approval.

### Independent PR review - PR: #295 (`83487f91730ceb67caaf070c106fe09892217827`), open - Task: `task-83e123d4` - Result: approved #### Summary The diff adds a scoped readiness signal and runtime Docker health check without changing the existing `/health` or `/api/v1/health` liveness contracts. Readiness is database/migration based, read-only, independent of owner setup, and returns stable `ready`/`not_ready` JSON with 200/503 and `Cache-Control: no-store`. The native Node healthcheck script uses only runtime-available Node globals and targets `/ready`. #### Acceptance criteria - [x] Runtime image declares a working Docker health check: `template/site/Dockerfile` copies `scripts/healthcheck.mjs` and declares `HEALTHCHECK ... CMD ["node", "scripts/healthcheck.mjs"]`; unit/static and local container evidence cover it. - [x] A healthy initialized site becomes ready: `/ready` returns 200 with `status: "ready"` and `checks.database: "pass"` for initialized DBs, including before owner setup. - [x] A site that cannot initialize a required dependency does not report ready: startup migration failures throw before serving; closed, missing/unmigrated, pending, locked, or unavailable DB cases return/not-report ready as expected. - [x] Liveness and readiness endpoints have documented, tested semantics: README documents `/health`, `/api/v1/health`, and `/ready`; focused route tests cover liveness, readiness, setup-gate bypass, status codes, JSON, and no-store. - [x] Optional disabled services do not make the site unready: readiness only checks the required database and does not contact fetch/S3/SMTP/remote peers; disabled ActivityPub/external-service test covers this. - [x] Container-level verification covers healthy and unhealthy states: supplied local-only container verifier/logs show healthy initialized, database-locked unhealthy/not_ready, recovery, and failed required DB initialization. - [x] Example deployment guidance uses the readiness signal for rollout checks: README instructs deployment rollouts to require `node scripts/healthcheck.mjs`/Docker health and route liveness to `/health`, readiness to `/ready`. #### Quality and security - Scope is aligned with the approved liveness/readiness, native Docker healthcheck, docs, and local-only container verification; no dependency, workflow, CI, or lint-config changes are present. - Readiness uses only `SELECT id FROM schema_migrations`; it does not open/create databases, run migrations, mutate schema, expose DB paths, credentials, or exception details. - Existing startup fail-fast database initialization remains before HTTP bind; enabled-feature startup validation is not weakened. - Test coverage is focused: new route/readiness cases, native script/static Docker cases using mocked fetch/process, startup migration failure, and template archive shipping regression. - Reviewed evidence: red logs for preimplementation failures, pre-PR/full local and unit-CI logs, Docker build log, and local-only container verification log/script. #### Blocking issues - None. #### Warnings - None. #### Final verdict Approved. Awaiting explicit human merge approval.
erik merged commit 7a1d3d464f into main 2026-10-04 22:54:01 -05:00
erik deleted branch feat/task-83e123d4-health-readiness 2026-10-04 22:54:01 -05:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
erik/slugkit!295
No description provided.