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

StatusMeaning
UP / passHealthy
WARNDegraded but serving
DOWN / failUnhealthy — 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

ProbePurposeIncludes
Liveness /livezShould I be restarted?Process responsive only
Readiness /readyzCan I receive traffic?DB, cache, downstream
Startup /startupzIs 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.

7. Returning Detailed Health Information

Example: RFC Health Check Response Format

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);