Application-Health-Monitoring
Überwacht einen eigenen Health-Endpunkt, der den internen Zustand deiner Anwendung meldet. Anders als Uptime-Checks, die nur schauen ob eine Seite erreichbar ist, geht Application-Health-Monitoring tiefer: Datenbank, Cache, Queue, externe Dienste -- alles im Blick.
So funktioniert es
Hoppla ruft deinen Health-Endpunkt im konfigurierten Intervall auf und wertet die JSON-Antwort aus. Der Endpunkt folgt dem Oh-Dear-Health-Check-Format: Er liefert einen finishedAt-Zeitstempel und ein checkResults-Array, in dem jeder Eintrag eine interne Komponente beschreibt (Datenbank, Cache, Queue, externer Dienst, …). Hoppla fasst die einzelnen Check-Status zu einem Gesamtergebnis zusammen.
Erwartetes Endpunkt-Format
Dein Health-Endpunkt sollte JSON zurückgeben -- mit einem finishedAt-Zeitstempel und einem checkResults-Array. Jeder Eintrag hat die Felder name, status sowie optional notificationMessage, shortSummary und meta:
{
"finishedAt": "2026-06-01T12:00:00+00:00",
"checkResults": [
{
"name": "Database",
"status": "ok",
"notificationMessage": "Database connection healthy",
"shortSummary": "OK",
"meta": { "connection_time_ms": 4 }
},
{
"name": "Queue",
"status": "warning",
"notificationMessage": "Queue backlog growing",
"shortSummary": "1.204 Jobs",
"meta": { "pending": 1204 }
}
]
}Status-Werte
Jeder Check im checkResults-Array meldet einen der folgenden status-Werte:
status | Bedeutung | Auswirkung |
|---|---|---|
ok | Komponente ist gesund | Bestanden |
warning | Komponente eingeschränkt, aber funktionsfähig | Gesamtwarnung |
failed | Komponenten-Check fehlgeschlagen | Gesamt-Incident |
crashed | Komponenten-Check abgestürzt / nicht ausführbar | Gesamt-Incident |
skipped | Check wurde übersprungen | Gilt als bestanden |
Hoppla ermittelt den Gesamtstatus aus den einzelnen Checks: fail (Incident), wenn ein Check failed oder crashed ist, warning, wenn ein Check warning meldet (oder der finishedAt-Zeitstempel veraltet ist), sonst ok.
Konfiguration
| Einstellung | Beschreibung | Standard |
|---|---|---|
| Health-Endpunkt-Pfad | Relativer Pfad, der an die Monitor-URL angehängt wird (absolute URLs werden aus SSRF-Sicherheitsgründen abgelehnt) | health |
| Health-Check-Secret | Wird deinem Endpunkt als Request-Header oh-dear-health-check-secret mitgeschickt | (keins) |
| Timeout | Maximale Wartezeit auf die Antwort (Sekunden, 1–60) | 10 |
| Stale-Schwelle | Warnung, wenn finishedAt älter als diese Anzahl Minuten ist | 5 |
| Check-Intervall | Wie oft Hoppla den Health-Endpunkt abfragt | 5 Minuten |
Der Health-Endpunkt ist immer ein relativer Pfad, der an die Monitor-URL angehängt wird -- der Pfad health beim Monitor https://example.com wird also zu https://example.com/health. Absolute URLs werden nicht akzeptiert.
Ergebnisse
| Feld | Beschreibung |
|---|---|
| finished_at | Der von deinem Endpunkt gemeldete finishedAt-Zeitstempel |
| checks | Die geparsten einzelnen Checks (name, status, message, short summary, meta) |
| checks_total | Anzahl der gemeldeten Checks |
| checks_failed | Anzahl der fehlgeschlagenen oder abgestürzten Checks |
| checks_warning | Anzahl der Checks im Warnzustand |
Beispielergebnis
Health check: https://example.com/health (200 OK)
finished_at: 2026-06-01T12:00:00+00:00
checks_total: 2
checks_failed: 0
checks_warning: 1
Checks:
Database: ok
Queue: warning (1.204 Jobs) ← flaggedAlarme
| Ereignis | Auslöser | Schweregrad |
|---|---|---|
incident.created | Ein Check meldet failed/crashed, der Endpunkt liefert 5xx oder die Anfrage schlägt komplett fehl | Incident |
warning.application_health | Ein Check meldet warning, der finishedAt-Zeitstempel ist veraltet, der Endpunkt liefert 401/403 (Secret falsch konfiguriert) oder 404/501 (nicht eingerichtet), oder der Body ist kein gültiges JSON | Warnung |
Eine 5xx-Antwort (oder ein Fehler auf Transportebene) eröffnet einen Incident. Ein 401 oder 403 bedeutet, dass das Secret falsch konfiguriert ist, ein 404 oder 501, dass der Endpunkt nicht eingerichtet ist -- beides erzeugt eine Warnung statt eines Incidents, genauso wie ein Nicht-JSON-Body oder ein veralteter finishedAt. Der Warnungs-Ereignistyp ist warning.application_health.
Implementierungsbeispiele
Laravel
Route::get('/health', function () {
$checks = [
['name' => 'Database', 'status' => rescue(fn () => DB::connection()->getPdo() ? 'ok' : 'failed', 'crashed')],
['name' => 'Cache', 'status' => rescue(fn () => Cache::store()->get('health-check') !== false ? 'ok' : 'failed', 'crashed')],
['name' => 'Queue', 'status' => rescue(fn () => Queue::size('default') >= 0 ? 'ok' : 'failed', 'crashed')],
];
return response()->json([
'finishedAt' => now()->toIso8601String(),
'checkResults' => $checks,
]);
});Express (Node.js)
app.get('/health', async (req, res) => {
const checkResults = [
{ name: 'Database', status: (await checkDatabase()) ? 'ok' : 'failed' },
{ name: 'Cache', status: (await checkRedis()) ? 'ok' : 'failed' },
{ name: 'Queue', status: (await checkQueue()) ? 'ok' : 'failed' },
];
res.json({
finishedAt: new Date().toISOString(),
checkResults,
});
});Best Practices
- Halte den Health-Endpunkt schlank -- keine aufwändigen Queries oder externe Aufrufe, die zu Timeouts führen könnten
- Setze Timeouts für jeden Komponenten-Check, damit der Endpunkt selbst nicht hängen bleibt
- Sichere den Endpunkt mit dem Health-Check-Secret ab -- Hoppla schickt es als Header
oh-dear-health-check-secret, sodass dein Endpunkt Anfragen ohne dieses Secret ablehnen kann - Liefere pro Teilsystem einen eigenen Check (je ein
checkResults-Eintrag), damit du sofort siehst, welche Komponente hakt