feat(health): add internal HTTP health endpoint for Docker/orchestrators - #217
feat(health): add internal HTTP health endpoint for Docker/orchestrators#217iagorobo24-hub wants to merge 5 commits into
Conversation
- Add startHealthServerMock/stopHealthServerMock to vi.hoisted - Mock config.health.port = 0 to disable server in tests - Mock src/health/server.js imports Fixes 11 test failures introduced by health endpoint feature.
- src/config.ts: BOT_HEALTH_PORT (default 3100, 0=disable) - src/app/bootstrap/start-bot-app.ts: start/stop health server integration - .env.example: document BOT_HEALTH_PORT - Dockerfile: EXPOSE 3100 - docker-compose.yml: healthcheck + BOT_HEALTH_PORT env + named volume
- tests/health/server.test.ts: 11 tests covering live/ready/health, degraded, port=0, lifecycle - tests/app/start-bot-app.test.ts: verify startHealthServer/stopHealthServer called
…ove dead code - /health/live: liveness, 200 always - /health/ready: readiness, 200 healthy / 503 degraded - /health: full payload, always 200 with status field - Remove 'eventLoop' check (was always true), rename to 'process' - Remove httpCode dead variable and contradictory comments - Bind 127.0.0.1 only (security)
- Remove trailing garbage (YAL/echo) - Healthcheck reads BOT_HEALTH_PORT env: 0=disabled/exit 0, else uses that port - docker compose config validates
|
@iagorobo24-hub thanks for the PR, I reviewed it and requesting some changes before merge: Major — src/config.ts:38-50 BOT_HEALTH_PORT values greater than 65535 are accepted by the configuration parser. For example, BOT_HEALTH_PORT=65536 reaches Please validate the port range as 0..65535. Value 0 should keep its special meaning and disable the server. Please also add a test for Minor — README.md:211-253, 480-484 BOT_HEALTH_PORT is documented in .env.example, but it is missing from the README environment variable table and Docker configuration Please add this variable to the README documentation. Minor — src/health/server.ts:124-130 If server.listen() fails, the module keeps the created server object in the global server variable. A later startHealthServer() call Please reset server and startTimeMs when the listen operation fails, so a retry is possible. |
Description of changes
Adds an internal HTTP health server (
src/health/server.ts) exposing three endpoints on configurable port (default 3100,BOT_HEALTH_PORT,0to disable):GET /health/live— Liveness probe (process alive), always 200, no dependency checksGET /health/ready— Readiness probe, 200 if healthy, 503 if degraded (OpenCode down)GET /health— Full health payload:{status, version, uptimeSeconds, checks: {process, opencode}}, always 200 with status field (Docker healthcheck convention)Integrated into app lifecycle (
start-bot-app.ts): starts after settings load, stops on shutdown signals. Used by DockerHEALTHCHECKindocker-compose.ymland by hermes-ops viahealth.type: http.Docker healthcheck reads
BOT_HEALTH_PORTenv var:http://127.0.0.1:3100/health0→ health server disabled, healthcheck exits 0 (container stays healthy)Motivation
UNKNOWNbecause bot doesn't expose health./live) + OpenCode dependency (/ready,/health) in standard endpoints./health/live+/health/readyfor Kubernetes/Docker Compose/swarm.Design choices
network_mode: host.fetch(Node 22) — no extra deps (curl/wgetnot in slim image).degraded(notunhealthy) when OpenCode is down — bot process is alive, can recover automatically.checks.process(liveness) +checks.opencode(dependency) — no false "event loop" claim.How it was tested
npm run lint✅npm run build✅npm test✅ (2 pre-existing flaky failures inevent-subscription-service.lifecycleunrelated)healthyBOT_HEALTH_PORT=3200→ healthcheck uses 3200,healthyBOT_HEALTH_PORT=0→ server disabled, healthcheck exits 0, container stayshealthy/healthreturnsdegraded,/health/readyreturns 503Checklist
mainnpm run lint,npm run build, andnpm testBOT_HEALTH_PORT,0disables server and passesdocker compose configvalidates (exit 0)