Implementing Health Checks
1. Creating Health Check Endpoint
Example: Minimal /health
app.get("/health", (req, res) => res.json({ status: "ok", uptime: process.uptime() }));
2. Returning Health Status
| Status | Meaning |
| UP / pass | Healthy |
| WARN | Degraded but serving |
| DOWN / fail | Unhealthy — remove from rotation |
3. Checking Database Connectivity
Example: pg ping
async function checkDb() {
try { await pool.query("SELECT 1"); return { status: "up" }; }
catch (err) { return { status: "down", error: err.message }; }
}
4. Checking External Dependencies
Example: Redis + downstream API
async function checkAll() {
const [db, cache, api] = await Promise.allSettled([
checkDb(),
redis.ping().then(() => ({ status: "up" })),
fetch("https://upstream/health", { signal: AbortSignal.timeout(2000) })
.then(r => ({ status: r.ok ? "up" : "down" }))
]);
return { db: db.value, cache: cache.value, api: api.value };
}
5. Implementing Liveness vs Readiness Probes
| Probe | Purpose | Includes |
Liveness /livez | Should I be restarted? | Process responsive only |
Readiness /readyz | Can I receive traffic? | DB, cache, downstream |
Startup /startupz | Is initial boot complete? | Migrations, warm-up |
Example: Three probes
app.get("/livez", (req, res) => res.sendStatus(200));
app.get("/readyz", async (req, res) => {
const checks = await checkAll();
const ok = Object.values(checks).every(c => c?.status === "up");
res.status(ok ? 200 : 503).json({ status: ok ? "ready" : "not_ready", checks });
});
6. Setting Health Check Timeouts
Example: AbortSignal.timeout
await fetch(url, { signal: AbortSignal.timeout(2000) });
Warning: Keep health checks fast (< 1s). Slow checks cause Kubernetes to flap pods in/out of rotation.
res.type("application/health+json").json({
status: "pass",
version: pkg.version,
releaseId: process.env.GIT_SHA,
checks: {
"database:responseTime": [{ status: "pass", observedValue: 12, observedUnit: "ms" }],
"cache:connected": [{ status: "pass" }]
}
});
8. Using express-healthcheck Package
Example: terminus
import { createTerminus } from "@godaddy/terminus";
createTerminus(server, {
healthChecks: { "/healthcheck": async () => checkAll() },
signals: ["SIGINT","SIGTERM"],
onSignal: () => pool.end()
});
9. Implementing Circuit Breaker Pattern
Example: opossum
import CircuitBreaker from "opossum";
const breaker = new CircuitBreaker(callUpstream, { timeout: 3000, errorThresholdPercentage: 50, resetTimeout: 30_000 });
breaker.fallback(() => ({ degraded: true }));
app.get("/data", async (req, res) => res.json(await breaker.fire(req.query)));
10. Monitoring Health Check Metrics
Example: prom-client
import client from "prom-client";
const healthGauge = new client.Gauge({ name: "app_health_up", help: "1 if healthy", labelNames: ["check"] });
setInterval(async () => {
const checks = await checkAll();
for (const [k, v] of Object.entries(checks)) healthGauge.labels(k).set(v?.status === "up" ? 1 : 0);
}, 15_000);