@dwtechs/healix-express
v0.2.0
Published
Open source health check and readiness routes for Express.js services.
Readme
Synopsis
Healix-express.js is an open source health check and readiness route for Express.js services.
- 🪶 Very lightweight
- ⚡ High performance
- 🔧 Easy to use
- 🧪 Thoroughly tested
- 🚚 Shipped as ECMAScript Express route
- 📝 Written in TypeScript
Support
- node: 22
This is the oldest targeted version.
Installation
$ npm i @dwtechs/healix-expressUsage
import express from "express";
import { healix } from "@dwtechs/healix-express";
import { errorHandler } from "@dwtechs/errandler-express";
const app = express();
app.disable("x-powered-by");
// Mandatory health check endpoint
app.use("/health", healix({
checks: {
db: () => pool.query("SELECT 1"),
},
}));
// Your application routes
app.use("/api/users", ...);
app.use("/api/products", ...);
// Error handling (must be last)
errorHandler(app);
app.listen(3000, () => {
console.log("Server running on port 3000");
console.log("Liveness available at http://localhost:3000/health");
console.log("Readiness available at http://localhost:3000/health/ready");
});Liveness vs readiness
Two questions, two endpoints — conflating them is why a service with a dead database keeps receiving traffic.
| | Question | Runs your checks? | On failure |
| :--- | :--- | :---: | :--- |
| GET / | Is the process alive? | no | orchestrator restarts the container |
| GET /ready | Can it serve traffic? | yes | instance is pulled from the load balancer |
Liveness deliberately ignores dependencies. If a database outage failed the liveness probe, every instance would be killed and restarted in a loop while the real problem sat elsewhere.
Options
healix({
checks?: Record<string, () => unknown | Promise<unknown>>; // default {}
timeoutMs?: number; // per-check budget, default 2000
readyPath?: string; // default "/ready"
});A check is healthy when it returns or resolves, and unhealthy when it throws or
rejects. Its resolved value is ignored. Checks run in parallel, each under its
own timeoutMs, so one hung dependency cannot hold the probe open.
Endpoint: GET /
Liveness. Never touches a dependency.
Response (200 OK):
{
status: "ok"; // Always "ok"
uptime: number; // Process uptime in seconds
timestamp: number; // Current Unix timestamp in milliseconds
}Endpoint: GET /ready
Readiness. Runs every configured check and reports them by name.
Response (200 OK / 503 Service Unavailable):
{
status: "ready" | "unavailable";
timestamp: number;
checks: Record<string, {
status: "ok" | "error";
durationMs: number;
error?: string; // present only when the check failed or timed out
}>;
}{
"status": "unavailable",
"timestamp": 1700000000000,
"checks": {
"db": { "status": "error", "durationMs": 2000, "error": "timed out after 2000ms" },
"cache": { "status": "ok", "durationMs": 0 }
}
}Health Check Script
The package includes a standalone health check script (test.js) designed for container orchestrators like Docker Compose and Kubernetes.
Usage with Docker Compose
Point the container healthcheck at readiness: a container that is running but cannot reach its database should be reported unhealthy, not left in rotation.
services:
my-service:
image: my-app
environment:
- PORT=3000
- HOST=127.0.0.1
- HEALTH_PATH=/health/ready
healthcheck:
test: ["CMD", "node", "/usr/src/app/node_modules/@dwtechs/healix-express.js/dist/test.js"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10sUsage with Kubernetes
The two probes must target different paths. Pointing readinessProbe at the
liveness endpoint makes it pass whenever the process is up, which defeats it.
livenessProbe:
exec:
command: ["node", "/usr/src/app/node_modules/@dwtechs/healix-express.js/dist/test.js"]
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 3
readinessProbe:
exec:
command: ["sh", "-c", "HEALTH_PATH=/health/ready node /usr/src/app/node_modules/@dwtechs/healix-express.js/dist/test.js"]
initialDelaySeconds: 5
periodSeconds: 10Environment Variables
PORT: The port your service listens on (default:3000)HOST: The host to check (default:127.0.0.1)HEALTH_PATH: The path to request (default:/health; use/health/readyfor readiness)HEALTH_TIMEOUT: Request timeout in milliseconds (default:2000)
The script makes an HTTP GET request to http://${HOST}:${PORT}${HEALTH_PATH} and exits with:
- Exit code
0if the check returns HTTP 200 - Exit code
1if the check fails or times out
Stack
| Purpose | Choice | Motivation | | :-------------- | :------------------------------------------: | -------------------------------------------------------------: | | repository | Github | hosting for software development version control using Git | | package manager | npm | default node.js package manager | | language | TypeScript | static type checking along with the latest ECMAScript features | | module bundler | Rollup | advanced module bundler for ES6 modules | | unit testing | Jest | delightful testing with a focus on simplicity |
