Hono with an existing Postgres pool
Install the runtime packages:health.ts. Pass your application’s existing pg.Pool to createProbes, then mount probes.app with app.route("/", probes.app) in your Hono application. Call probes.kit.start() once during long-lived process startup to enable the scheduled database check.
health.ts
pg, consider connectionTimeoutMillis: 1_000, query_timeout: 1_500, and statement_timeout: 1_500. Handle pool errors in your application without logging credentials. A healthzkit deadline does not necessarily cancel the underlying query; see driver timeouts.
Choose the adapter for your driver
Install the adapter and its peer driver. Follow the linked page for client options and required peer versions; import from the documented subpath.
See Postgres, Drizzle, and Prisma for complete examples. Other supported drivers have their own pages in the Adapters navigation. Reuse the existing client rather than creating a new pool on every health request.
Select probes and execution mode
- Point Kubernetes liveness at
/healthz/live, readiness at/healthz/ready, and startup at/healthz/startup. - Put external dependencies in readiness. Keep liveness focused on whether restarting this process would help.
- Add at least one real readiness check. With the default rollup, a probe with no matching checks succeeds.
- In a long-lived Node process, call
kit.start()once. Scheduled checks serve cached results; failure detection includes the refresh interval. See Scheduling. - In Workers and serverless handlers, run checks on demand without
kit.start()or background timers. Choose drivers supported by that runtime; this Nodepg.Poolrecipe is for long-lived Node applications. See Framework guides for route wiring. - HTTP output hides errors and metadata in this example. Internal results and hooks retain diagnostics. See Responses and HTTP.
Shut down in order
OnSIGTERM or SIGINT, call kit.beginDrain() to make readiness fail while keeping liveness available. Give your load balancer time to remove the instance, then stop accepting requests and wait for active HTTP handlers to finish. Call await kit.close() to stop scheduling, wait for pending checks, and dispose adapter-owned resources. Finally, close the application’s shared pool with await pool.end().
Use an application-level shutdown deadline shorter than the Kubernetes termination grace period: a driver that ignores cancellation can keep pending checks alive. kit.close() is terminal and idempotent. kit.stop() stops scheduling and clears cached results without disposing adapters; probes remain usable on demand, and kit.start() can restart scheduling. Supplied clients remain yours to close, and cleanup errors must be handled.
The runnable Node example includes server bootstrap, pool configuration, signal handling, and Kubernetes configuration.
Verify the integration
- With the database available, confirm readiness returns 200 and queries the same pool as application traffic.
- Make the database unavailable. After the scheduled refresh and check deadline, readiness should return 503 while liveness remains 200.
- Confirm public responses contain no database errors or metadata. HEAD requests should have no body; unsupported methods should return 405.
- Begin draining and confirm readiness returns 503 immediately. Confirm the server drains before the shared pool closes.