patterntypescriptMajor
Health check aggregation: /health returns structured status for all dependencies
Viewed 0 times
health checkreadiness probeliveness probedependency check503kubernetes healthstructured healthtermination handler
Problem
A service's
/health endpoint returns 200 OK even when its database connection is broken. Kubernetes marks the pod as ready and sends traffic to it. All requests fail.Solution
Implement a structured health check that tests each critical dependency and aggregates results. Return 200 only when all required dependencies are healthy; return 503 for degraded state.
app.get('/health', async (req, res) => {
const checks = await Promise.allSettled([
db.raw('SELECT 1').then(() => ({ name: 'postgres', status: 'ok' })),
redis.ping().then(() => ({ name: 'redis', status: 'ok' })),
]);
const results = checks.map((c, i) =>
c.status === 'fulfilled' ? c.value : { name: ['postgres','redis'][i], status: 'error', error: c.reason?.message }
);
const healthy = results.every(r => r.status === 'ok');
res.status(healthy ? 200 : 503).json({ status: healthy ? 'ok' : 'degraded', checks: results });
});Why
Kubernetes uses the readiness probe response to decide whether to route traffic. A 503 removes the pod from the load balancer until dependencies recover. Without this, broken pods receive traffic silently.
Gotchas
- Health checks themselves must be fast and have their own timeouts — a slow DB health check can cause false positives
- Distinguish liveness (is the process alive?) from readiness (are dependencies reachable?) — map to separate endpoints
- Do not include optional/degraded-tolerant dependencies as health-check blockers
- Expose a /metrics endpoint (Prometheus format) alongside /health for deeper observability
Context
Any microservice deployed on Kubernetes or behind a load balancer that has external dependencies
Revisions (0)
No revisions yet.