Health Checks
Der Management-Server stellt zwei Health-Endpunkte bereit:
GET /health— Liveness. Gibt 200 zurück, wenn der Prozess operational ist.GET /ready— Readiness. Gibt 200 zurück, wenn der Pod bereit ist, Traffic zu empfangen (Cluster up + eigene Checks bestehen).
Das Framework registriert ein paar Defaults (cluster-up für ready), plus du kannst eigene Checks für app-spezifische Health einklinken.
import { HttpManagement } from 'actor-ts';
const { health } = await HttpManagement.start(system, { port: 8558 });
health.addCheck('database', async () => { const ok = await db.ping(); return ok ? { ok: true } : { ok: false, reason: 'db unreachable' };});
health.addCheck('cache', async () => { try { await redis.ping(); return { ok: true }; } catch (e) { return { ok: false, reason: (e as Error).message }; }});Wenn irgendein Check { ok: false } zurückgibt, antwortet
der Endpunkt mit 503 und einem JSON-Body, der die
fehlgeschlagenen Checks auflistet.
Die Check-Signatur
Abschnitt betitelt „Die Check-Signatur“type HealthCheck = () => Promise<HealthCheckResult>;
interface HealthCheckResult { ok: boolean; reason?: string; // menschenlesbare Fehlerbeschreibung details?: unknown; // strukturierte Info für Diagnostik}Checks sind async — gib eine Promise zurück. Lang laufende Checks blockieren die Response, also halte sie schnell (sub-Sekunde, idealerweise < 100 ms).
Liveness vs Readiness
Abschnitt betitelt „Liveness vs Readiness“| Probe | Was sie beantwortet | Was K8s bei Fehler macht |
|---|---|---|
Liveness (/health) | „Ist dieser Prozess fundamental kaputt?” | Pod neu starten. |
Readiness (/ready) | „Sollte dieser Pod gerade Traffic bekommen?” | Routing stoppen zu diesem Pod (Pod laufen lassen). |
Unterschiedliche Semantik treibt unterschiedliche Checks:
- Liveness sollte nur bei nicht behebbaren Problemen fehlschlagen — Actor-System gecrashed, Deadlock erkannt, fundamentale Invarianten gebrochen. Restart ist der einzige Fix.
- Readiness darf bei transienten Problemen fehlschlagen — DB kurz nicht erreichbar, Cache wärmt sich auf, Cluster rejoint. Kein Restart nötig; einfach noch nicht hierhin routen.
Stecke nicht alle Checks in beide — einen Pod neu zu starten, weil die externe DB geblinkt hat, ist falsch; der DB-Blinker geht vorbei. Stecke DB-Checks nur in Readiness.
Eingebauter Readiness-Check
Abschnitt betitelt „Eingebauter Readiness-Check“Wenn der Management-Server mit einem cluster konfiguriert ist,
schlägt der Default-Readiness-Check fehl, falls der lokale Node
nicht Up ist:
GET /ready{ ok: false, reason: 'cluster not joined yet' }Gibt 200 zurück, sobald SelfUp feuert. Das ist der kanonische
„warte auf den Cluster”-Check.
Mehrere Checks
Abschnitt betitelt „Mehrere Checks“health.addCheck('database', dbCheck);health.addCheck('cache', cacheCheck);health.addCheck('downstream-api', apiCheck);Alle Checks laufen parallel, wenn der Endpunkt getroffen wird. Die Response enthält Per-Check-Status:
{ "ok": false, "checks": { "cluster": { "ok": true }, "database": { "ok": false, "reason": "connection refused" }, "cache": { "ok": true }, "downstream-api": { "ok": true } }}Das Aggregat-ok ist true, wenn jeder Check wahr ist.
Nur-Liveness-Checks
Abschnitt betitelt „Nur-Liveness-Checks“health.addCheck('actor-system-alive', async () => { return { ok: !system.isTerminated, reason: system.isTerminated ? 'system terminated' : undefined, };}, { liveness: true, readiness: false });Das optionale zweite Argument routet einen Check zu
Liveness-only (Default readiness: true) oder
Readiness-only.
Der „System nicht terminated”-Check wird vom Framework automatisch als Liveness-only registriert — es ist ein nicht behebbarer Zustand.
Tests für Checks
Abschnitt betitelt „Tests für Checks“import { TestKit } from 'actor-ts/testkit';
it('Health Check schlägt fehl, wenn DB unten ist', async () => { const tk = TestKit.create(); const { health } = await HttpManagement.start(tk.system, { port: 0 });
health.addCheck('db', async () => ({ ok: false, reason: 'mock' }));
const result = await health.run(); expect(result.ok).toBe(false); expect(result.checks!.db).toEqual({ ok: false, reason: 'mock' });
await tk.shutdown();});HealthCheckRegistry.run() exponiert die gleiche Logik wie der
Endpunkt — nützlich für Unit-Tests deiner Checks.
Timeouts
Abschnitt betitelt „Timeouts“health.addCheck('slow-thing', slowCheck, { timeoutMs: 2_000 });Per-Check-Timeout. Ein Check, der das Timeout überschreitet,
wird als { ok: false, reason: 'timeout' } behandelt.
Ohne Timeout blockiert ein hängender Check die ganze
/health-Response — und löst irgendwann das eigene Probe-
Timeout von K8s (10 s Default) und einen Restart aus. Setze
Check-Timeouts konservativ.
Wo es weitergeht
Abschnitt betitelt „Wo es weitergeht“- Management — Überblick — das größere Bild.
- HTTP-Endpunkte — die volle Endpunkt-Referenz.
- Kubernetes-Deployment — die Probe-Konfiguration, mit der das gepaart wird.