Health checks
Este conteúdo não está disponível em sua língua ainda.
The management routes expose two health endpoints:
GET /health— liveness. Returns 200 if the process is operational.GET /ready— readiness. Returns 200 if the pod is ready to receive traffic (cluster up + every readiness check passes).
managementRoutes(...) hands you a HealthCheckRegistry (the
health field) where you register custom checks for
app-specific health:
import { managementRoutes } from 'actor-ts';
const { routes, health } = managementRoutes(system, cluster);
health.addReadiness(async () => { const ok = await db.ping(); return { name: 'database', status: ok, detail: ok ? undefined : 'db unreachable' };});
health.addReadiness(async () => { try { await redis.ping(); return { name: 'cache', status: true }; } catch (e) { return { name: 'cache', status: false, detail: (e as Error).message }; }});
await system.http(8558).bind(routes);When any check returns status: false, the corresponding
endpoint returns 503 with a JSON body listing every check’s
result.
The check signature
Section titled “The check signature”type HealthCheckFn = () => Promise<HealthCheckResult> | HealthCheckResult;
type HealthCheckResult = { name: string; // identifies the check in the response status: boolean; // true = healthy detail?: string; // human-readable note, usually on failure};A check may be sync or async. addLiveness / addReadiness each
return an unsubscribe function — call it to remove the check
again:
const remove = health.addReadiness(() => ({ name: 'warmup', status: warmedUp }));// ... once warm-up is permanently done:remove();Long-running checks block the response, so keep them fast (sub-second, ideally < 100 ms).
Liveness vs readiness
Section titled “Liveness vs readiness”| Probe | What it answers | What K8s does on failure |
|---|---|---|
Liveness (/health) | “Is this process fundamentally broken?” | Restart the pod. |
Readiness (/ready) | “Should this pod receive traffic right now?” | Stop routing to this pod (keep it running). |
A check is liveness or readiness depending on which method you
call — addLiveness or addReadiness. They are separate
lists; to run the same check for both, register it with both.
Different semantics drive different checks:
- Liveness should only fail for unrecoverable issues —
actor system crashed, deadlock detected, fundamental invariants
broken. Restart is the only fix. Register these with
addLiveness. - Readiness can fail for transient issues — DB briefly
unreachable, cache warming up, cluster rejoining. No restart
needed; just don’t route here yet. Register these with
addReadiness.
Don’t register DB / downstream checks as liveness — restarting a pod because the external DB blipped is wrong; the blip will pass.
Cluster readiness
Section titled “Cluster readiness”/ready also reports a clusterReady flag, computed from cluster
membership — independent of your registered checks. It’s
false until the local node reaches the Up state (and always
true when the routes were built without a cluster):
GET /ready→ 503{ "status": "DOWN", "clusterReady": false, "checks": [] }Returns clusterReady: true (and 200, if your readiness checks
also pass) once the node is Up — the canonical “wait for the
cluster” gate.
Multiple checks
Section titled “Multiple checks”health.addReadiness(dbCheck);health.addReadiness(cacheCheck);health.addReadiness(downstreamApiCheck);All readiness checks run in parallel when /ready is hit.
The response lists each check’s result:
{ "status": "DOWN", "clusterReady": true, "checks": [ { "name": "database", "status": false, "detail": "connection refused" }, { "name": "cache", "status": true }, { "name": "downstream-api", "status": true } ]}The aggregate is UP iff clusterReady and every check’s
status is true.
Testing checks
Section titled “Testing checks”import { HealthCheckRegistry } from 'actor-ts';
it('readiness fails when the DB is down', async () => { const health = new HealthCheckRegistry(); health.addReadiness(async () => ({ name: 'db', status: false, detail: 'mock' }));
const results = await health.checkReadiness(); expect(results).toEqual([{ name: 'db', status: false, detail: 'mock' }]);});checkLiveness() / checkReadiness() run the registered checks
and return the HealthCheckResult[] the endpoints aggregate —
handy for unit-testing checks in isolation. A check that throws is
caught and reported as { name: 'unknown', status: false, detail }.
The isHealthy(results) helper is the same all-pass predicate the
endpoints use.
Timeouts
Section titled “Timeouts”There is no built-in per-check timeout — a hung check blocks
the whole /health (or /ready) response. For a check that can
stall, race it against your own deadline:
health.addReadiness(async () => { const status = await Promise.race([ slowProbe().then(() => true), new Promise<boolean>((r) => setTimeout(() => r(false), 2_000)), ]); return { name: 'downstream', status };});Without a guard, a stuck check eventually trips K8s’s own probe timeout (10 s default) and triggers a restart. Keep checks fast.
Where to next
Section titled “Where to next”- Management overview — the bigger picture.
- HTTP endpoints — the full endpoint reference.
- Kubernetes deployment — the probe configuration this pairs with.
