Cronjobs überwachen: Heartbeat-Monitoring in der Praxis
Cronjobs überwachen mit Heartbeat-Monitoring: Wie der Dead-Man's-Switch funktioniert, typische Fehlerarten und Best Practices für cron, systemd und Kubernetes.
Warum Cronjobs stille Ausfälle sind
Ein abgestürzter Webserver fällt sofort auf: Besucher sehen Fehlermeldungen, das Uptime Monitoring schlägt Alarm, Support-Tickets laufen ein. Ein Cronjob, der nicht mehr läuft, fällt dagegen niemandem auf — bis es zu spät ist.
Das nächtliche Backup, der Rechnungsversand am Monatsersten, der Queue-Worker, der Import aus dem Warenwirtschaftssystem: All diese Jobs haben keinen Port, keine URL und keine Nutzer, die sich beschweren. Wenn sie ausfallen, entsteht kein Fehler — es passiert einfach nichts. Und genau das macht sie gefährlich:
- Ein Backup-Skript, das seit drei Monaten nicht mehr läuft, bemerkst Du in dem Moment, in dem Du das Backup brauchst.
- Ein hängender Rechnungslauf fällt erst auf, wenn Kunden anrufen, warum keine Rechnung kam.
- Ein gestoppter Queue-Worker staut still Tausende Jobs auf, bis der Speicher voll ist.
Klassisches Monitoring hilft hier nicht weiter. Ein HTTP-Check kann prüfen, ob Deine Website antwortet — aber kein Monitoring-System der Welt kann von außen sehen, ob ein Skript auf Deinem Server heute Nacht gelaufen ist. Die Lösung ist eine Umkehrung des Prinzips: Nicht das Monitoring fragt den Job — der Job meldet sich beim Monitoring.
Wie Heartbeat-Monitoring funktioniert
Heartbeat-Monitoring (auch Dead-Man's-Switch genannt, nach dem Totmannschalter im Führerstand einer Lok) basiert auf einem ausbleibenden Signal: Der Job sendet nach jedem erfolgreichen Lauf ein kurzes Lebenszeichen. Bleibt das Lebenszeichen aus, wird alarmiert.
Ping-URL und Erwartungsfenster
Der Ablauf ist in drei Schritten erklärt:
- Ping-URL: Das Monitoring stellt für jeden Job eine eindeutige URL bereit. Der Job ruft sie am Ende per HTTP auf — ein einzelnes
curlgenügt. - Erwartungsfenster: Aus dem Zeitplan des Jobs (Cron-Expression oder "alle 15 Minuten") berechnet das Monitoring, wann der nächste Ping fällig ist.
- Alarm: Kommt der Ping nicht innerhalb des Fensters an, gilt der Job als ausgefallen — und das Alerting greift.
In der Crontab sieht das so aus:
# Backup um 2:00 Uhr — Ping NUR bei Erfolg
0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 5 -o /dev/null https://monitoring.example.de/ping/a1b2c3
Das && ist hier kein Detail, sondern der Kern des Setups — dazu gleich mehr.
Grace Period richtig dimensionieren
Kein Job läuft immer exakt gleich lang. Damit natürliche Schwankungen keinen Fehlalarm auslösen, gibt es die Grace Period: einen Puffer nach dem Soll-Zeitpunkt, bevor der Alarm ausgelöst wird.
Die Faustregel: Orientiere Dich an der maximalen realistischen Laufzeit, nicht am Durchschnitt. Läuft Dein Backup normalerweise 5 bis 15 Minuten, ist eine Grace Period von 30 Minuten vernünftig. Zu knapp bemessen produziert sie Fehlalarme und damit Alert Fatigue — zu großzügig verschenkt sie Reaktionszeit. Bei stark schwankenden Jobs sind Start-Pings plus Laufzeit-Limit die bessere Wahl als eine überdehnte Grace Period.
Start- und Ende-Pings
Fortgeschrittene Setups senden zwei Signale: eines beim Start des Jobs, eines am Ende. Das macht drei Zustände unterscheidbar, die ein einzelner Ping nicht trennen kann:
| Signal-Muster | Bedeutung |
|---|---|
| Kein Start-Ping | Job wurde nie gestartet (cron-Daemon, Crontab, Server) |
| Start-Ping ohne Ende-Ping | Job gestartet, aber abgestürzt oder hängt |
| Start + Ende, aber zu lange Dauer | Job läuft, aber etwas bremst ihn |
Als Bonus wird die Laufzeit messbar — und ein schleichend langsamer werdender Job fällt auf, bevor er ins Zeitfenster des nächsten Laufs hineinwächst. Einige Dienste akzeptieren zusätzlich einen expliziten Fail-Ping mit Exit-Code: Der Job meldet seinen Fehler dann sofort, statt erst nach Ablauf des Erwartungsfensters aufzufallen.
Die vier Fehlerarten eines Cronjobs
Cronjobs scheitern auf vier grundsätzlich verschiedene Arten — und jede braucht einen anderen Erkennungsmechanismus:
- Der Job läuft gar nicht. Server down, cron-Daemon gestoppt, Crontab beim Deployment überschrieben, Tippfehler im Zeitplan. Das Tückische: Es entsteht kein Log-Eintrag, denn es läuft ja nichts. Diese Fehlerklasse ist nur per Dead-Man's-Switch erkennbar.
- Der Job hängt oder läuft zu lang. Eine hängende Datenbank-Query, ein blockierter Mount, ein nicht freigegebener Lock. Erkennung: Start-Ping ohne Ende-Ping oder eine gerissene Laufzeit-Grenze.
- Der Job läuft zu oft. Doppelt eingetragene Crontab, derselbe Job auf zwei Servern, Überlappung mit dem vorherigen Lauf. Erkennung: Pings außerhalb des erwarteten Zeitplans.
- Der Job läuft durch — aber das Ergebnis ist falsch. Der gefährlichste Fall: Exit-Code 0, Ping gesendet, aber das Backup ist eine 0-Byte-Datei. Hier hilft kein Monitoring von außen — das Skript selbst muss sein Ergebnis validieren (Dateigröße, Zeilenzahl, Checksumme) und bei Verdacht mit einem Fehler aussteigen.
Best Practices für zuverlässige Pings
&& statt Semikolon
Der wichtigste Einzeltipp in diesem Guide. Diese beiden Zeilen sehen fast gleich aus und trennen ein funktionierendes Monitoring von einem nutzlosen:
# RICHTIG: Ping nur, wenn backup.sh mit Exit 0 endet
backup.sh && curl -fsS https://monitoring.example.de/ping/a1b2c3
# FALSCH: Ping wird IMMER gesendet — auch wenn backup.sh fehlschlägt
backup.sh ; curl -fsS https://monitoring.example.de/ping/a1b2c3
Mit dem Semikolon meldet der Job auch dann Erfolg, wenn das Backup fehlgeschlagen ist. Das Monitoring zeigt dauerhaft Grün — und ist damit schlimmer als gar keins, weil es falsche Sicherheit vermittelt.
curl richtig aufrufen
Der Ping selbst darf den Job weder aufhalten noch brechen. Die bewährte Flag-Kombination:
curl -fsS -m 10 --retry 5 -o /dev/null https://monitoring.example.de/ping/a1b2c3
-m 10— Timeout: Der Ping hängt nie länger als 10 Sekunden, selbst wenn das Monitoring nicht erreichbar ist.--retry 5— transiente Netzwerkfehler werden abgefangen, statt einen Fehlalarm zu erzeugen.-fsS— still im Erfolgsfall, aber Fehler bleiben im Log sichtbar.-o /dev/null— die Antwort interessiert nicht, nur die Zustellung.
Überlappungen und Hänger verhindern
Zwei kleine Standard-Werkzeuge lösen zwei große Problemklassen:
# flock: verhindert, dass ein neuer Lauf startet, solange der alte läuft
0 * * * * flock -n /tmp/import.lock /usr/local/bin/import.sh && curl -fsS https://…/ping/import
# timeout: ein Job kann nie endlos hängen (Exit 124 nach 25 Minuten)
0 2 * * * timeout 25m /usr/local/bin/backup.sh && curl -fsS https://…/ping/backup
Exit-Codes ehrlich halten
Bash-Skripte maskieren Fehler gern — eine Pipe wie pg_dump | gzip liefert den Exit-Code von gzip, selbst wenn pg_dump gescheitert ist. Drei Zeilen am Skript-Anfang schaffen Ordnung:
#!/usr/bin/env bash
set -euo pipefail
Damit bricht das Skript bei jedem Fehler, jeder ungesetzten Variable und jedem Pipe-Fehler ab — und der Erfolgs-Ping hinter dem && bleibt aus, genau wie es sein soll.
systemd-Timer und Kubernetes CronJobs
systemd-Timer sind auf modernen Linux-Systemen der Nachfolger klassischer Cronjobs und bringen von Haus aus mehr mit: Logs via journalctl, Persistent=true zum Nachholen verpasster Läufe und OnFailure=-Hooks für lokale Reaktionen. Was sie nicht können: von außen alarmieren. Fällt der ganze Server aus, meldet ein lokaler Hook gar nichts. Der externe Heartbeat bleibt also auch hier Pflicht — sauber eingebunden über ExecStartPost=, das nur nach erfolgreichem Lauf ausgeführt wird.
Kubernetes CronJobs haben eigene Fehlerklassen, die klassisches cron nicht kennt: Image-Pull-Fehler, Pods, die wegen fehlender Ressourcen ewig in Pending hängen, verpasste startingDeadlineSeconds oder eine falsch gewählte concurrencyPolicy. kubectl get cronjob zeigt nur den letzten Status — eine Historie oder Alarmierung liefert Kubernetes nicht. Der einfachste robuste Weg ist derselbe wie überall: ein && curl …-Ping am Ende des Container-Commands, ausgewertet von einem externen Heartbeat-Monitoring.
Tools im Vergleich
Die Nische ist gut besetzt — ein ehrlicher Blick auf die kostenlosen Einstiege (Stand Juli 2026):
| Tool | Kostenlos | Bezahlt ab |
|---|---|---|
| LIVCK | Self-Hosted 0 € (kommerziell erlaubt) · Cloud Free: 20 Services (Public Beta) | Self-Hosted-Lizenz ab 9,90 €/Monat |
| Healthchecks.io | 20 Checks, 3 Team-Member | Business $20/Monat (100 Checks) |
| Cronitor | 5 Monitore, 5-Min-Intervall | $2/Monitor + $5/User |
| Dead Man's Snitch | 1 Snitch, nur Standard-Intervalle | $5/Monat (3 Snitches) |
| Sentry Crons | 1 Cron-Monitor | $0,78/Monitor (nur auf Paid-Plänen) |
| UptimeRobot | Heartbeat im Free-Plan, 5-Min-Intervall | Pro für 1-Min-Checks |
| Better Stack | 10 Heartbeats, 3-Min-Intervall | +$17/Monat je weitere 10 |
Bemerkenswert im Kleingedruckten: Healthchecks.io ist Open Source und self-hostbar — der Klassiker für Sparfüchse, allerdings ein reines Cronjob-Tool ohne Uptime-Monitoring und Statuspage. Cronitor ist im reinen Cronjob-Monitoring am ausgereiftesten, rechnet aber pro Monitor und User ab — bei wachsenden Setups wird das schnell teuer. Und bei UptimeRobot gilt der Free-Plan nur für nicht-kommerzielle Nutzung.
Cronjob-Monitoring mit LIVCK
LIVCK bringt Heartbeat-Monitoring als einen von sieben Check-Typen mit — neben HTTP(S), TCP, Ping, DNS, SSL und Manual/API. Der Zeitplan versteht einfache Intervalle oder echte Cron-Ausdrücke mit Zeitzone, und über die Signale /start und /fail samt Exit-Code unterscheidet LIVCK „nie gestartet" von „abgestürzt" — inklusive Laufzeitmessung und Maximal-Laufzeit gegen hängende Jobs. Bleibt das erwartete Signal aus, greift die Alarmierung über E-Mail, SMS, Sprachanruf, Slack, Microsoft Teams, Telegram oder Discord.
Der eigentliche Unterschied zu den Spezialisten liegt im Gesamtpaket: Ein ausgefallener Heartbeat ist bei LIVCK nicht nur ein interner Alarm, sondern kann direkt in die Statuspage und das Incident Management einfließen — vom stillen Cronjob-Ausfall zur transparenten Kommunikation in einem Tool. Beim Betrieb hast Du die Wahl: Self-Hosted via Docker Compose (0 €, kommerzielle Nutzung erlaubt — läuft auf einem Hetzner-Server ab unter 5 €/Monat), Managed Service auf deutschen Servern oder die LIVCK Cloud mit Free-Plan (20 Services) — Public Beta, Zugang über die Waitlist. Da LIVCK aus Deutschland kommt und DSGVO by Design arbeitet, bleiben Deine Monitoring-Daten dort, wo sie hingehören.
Gerade nach dem Aus von Freshping ist der Self-Hosted-Ansatz mehr als eine Geschmacksfrage: Ein Monitoring auf dem eigenen Server kann Dir kein Anbieter abschalten.
Fazit
Cronjobs sind die stillsten Ausfälle in jeder Infrastruktur: kein Port, keine Fehlermeldung, kein verärgerter Nutzer — nur ein Job, der irgendwann einfach nicht mehr läuft. Heartbeat-Monitoring dreht das Prinzip um und macht das Ausbleiben selbst zum Alarm-Signal.
Die Essenz aus diesem Guide: Ping nur bei Erfolg senden (&&, nie ;), curl mit Timeout und Retries absichern, die Grace Period an der maximalen statt der durchschnittlichen Laufzeit ausrichten, Überlappungen mit flock und Hänger mit timeout verhindern — und Skripte mit set -euo pipefail ehrlich halten. Wer zusätzlich Start-Pings nutzt, unterscheidet "nie gestartet" von "abgestürzt" und sieht Laufzeit-Trends, bevor sie zum Problem werden.
Und wie beim Uptime Monitoring gilt auch hier: Das Monitoring gehört auf eine unabhängige Infrastruktur — sonst fällt es gemeinsam mit den Jobs aus, die es überwachen soll.
Verwandte Artikel
Incident Management: Prozess, Rollen und Kommunikation
Incident Management erklärt: Lifecycle, Schweregrade, Rollen, Eskalation, Post-Mortem und Kennzahlen wie MTTR — plus professionelle Incident-Kommunikation.
Self-HostingSelf-Hosted Statuspage — Warum, wie und welche Lösung?
Self-Hosted vs. Cloud Statuspage: Vorteile, Anforderungen, Docker-Setup und Vergleich mit Open-Source-Alternativen wie Uptime Kuma und CachetHQ.
MonitoringUptime Monitoring: Grundlagen, Check-Typen & Tool-Wahl
Uptime Monitoring erklärt: Check-Typen (HTTP, TCP, Heartbeat), Intervalle, Alerting und worauf es bei der Tool-Wahl ankommt — inkl. DSGVO und Self-Hosting.
Verwandte Vergleiche
Bereit für Deine eigene Statuspage?
LIVCK: Monitoring und Statuspage aus Deutschland. Self-Hosted, Managed oder Cloud. DSGVO by Design.
Keine Kreditkarte erforderlich. Keine Lizenzkosten.