Zum Inhalt springen
Monitoring

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.

12 Min. Lesezeit 2026-07-03

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:

  1. Ping-URL: Das Monitoring stellt für jeden Job eine eindeutige URL bereit. Der Job ruft sie am Ende per HTTP auf — ein einzelnes curl genügt.
  2. Erwartungsfenster: Aus dem Zeitplan des Jobs (Cron-Expression oder "alle 15 Minuten") berechnet das Monitoring, wann der nächste Ping fällig ist.
  3. 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-MusterBedeutung
Kein Start-PingJob wurde nie gestartet (cron-Daemon, Crontab, Server)
Start-Ping ohne Ende-PingJob gestartet, aber abgestürzt oder hängt
Start + Ende, aber zu lange DauerJob 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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):

ToolKostenlosBezahlt ab
LIVCKSelf-Hosted 0 € (kommerziell erlaubt) · Cloud Free: 20 Services (Public Beta)Self-Hosted-Lizenz ab 9,90 €/Monat
Healthchecks.io20 Checks, 3 Team-MemberBusiness $20/Monat (100 Checks)
Cronitor5 Monitore, 5-Min-Intervall$2/Monitor + $5/User
Dead Man's Snitch1 Snitch, nur Standard-Intervalle$5/Monat (3 Snitches)
Sentry Crons1 Cron-Monitor$0,78/Monitor (nur auf Paid-Plänen)
UptimeRobotHeartbeat im Free-Plan, 5-Min-IntervallPro für 1-Min-Checks
Better Stack10 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.

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.