Fehlerbehebung · systemd
systemd-Timer läuft nicht? In fünf Schritten diagnostizieren
Warum ein systemd-Timer nicht auslöst — nicht aktiviert, OnCalendar-Syntax, fehlendes daemon-reload, fehlschlagende Service-Unit, User-Timer ohne Lingering — und die jeweilige Lösung.
systemd-Timer sind der moderne Cron-Ersatz unter Linux — mit besserem Logging und mehr Fehlermodi, die man kennen sollte. Arbeiten Sie die Punkte der Reihe nach ab.
Diagnose in 30 Sekunden:
| Symptom | Wahrscheinlichste Ursache | Abschnitt |
|---|---|---|
Timer fehlt in list-timers, oder NEXT ist n/a | Nicht aktiviert oder kaputtes OnCalendar | §1 / §3 |
| Änderungen scheinen wirkungslos | Fehlendes daemon-reload | §2 |
| LAST zeigt einen Lauf, aber nichts passierte | Die zugehörige Service-Unit schlug fehl | §4 |
| Funktioniert, stoppt dann zufällig | User-Timer ohne Lingering | §5 |
| Läuft Minuten später als geplant | AccuracySec / RandomizedDelaySec | §5 |
1. Ist der Timer überhaupt aktiviert und gestartet?
Der Klassiker: Die Unit-Dateien existieren, aber niemand hat den Timer gestartet.
systemctl list-timers --all # ist Ihr Timer gelistet? NEXT gesetzt?
systemctl status backup.timer # "Active: active (waiting)" ist das Ziel
sudo systemctl enable --now backup.timer
enable allein startet erst beim nächsten Boot; enable --now sofort.
Zeigt NEXT den Wert n/a, ist der Timer geladen, hat aber keinen gültigen
Trigger — meist ein Syntaxproblem (§3).
Zwei verwandte Fallen:
- Der Timer ist aktiviert, aber die Unit-Datei hat keine
[Install]-Sektion — dann bewirktenablenichts Sinnvolles. Ein Timer brauchtWantedBy=timers.targetunter[Install]. - Der Timer wurde maskiert (
systemctl statuszeigtmasked) — typisch durch Paketmanager oder Admins. Erstsystemctl unmask backup.timer.
2. Haben Sie nach dem Editieren daemon-reload ausgeführt?
systemd liest Unit-Dateien einmal. Änderungen an backup.timer oder
backup.service bewirken nichts, bis:
sudo systemctl daemon-reload
sudo systemctl restart backup.timer
Am härtesten trifft das Konfigurationsmanagement (Ansible, Puppet), das
Unit-Dateien schreibt, aber kein Reload auslöst — Datei und geladene Unit
divergieren still. systemctl show backup.timer -p NeedDaemonReload verrät, ob
die geladene Version veraltet ist.
3. Den OnCalendar-Ausdruck validieren
OnCalendar ist keine Cron-Syntax. 0 3 * * * bedeutet stillschweigend
etwas anderes oder parst gar nicht. Das Format ist
Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde:
[Timer]
OnCalendar=*-*-* 03:00:00 # täglich um 03:00
OnCalendar=Mon *-*-* 09:00:00 # montags um 09:00
OnCalendar=*-*-* *:0/15:00 # alle 15 Minuten
OnCalendar=Sat,Sun *-*-* 10:00 # am Wochenende um 10:00
Immer mit dem eingebauten Validator prüfen — er zeigt auch die nächste Auslösung:
systemd-analyze calendar "Mon *-*-* 09:00:00"
Failed to parse calendar specification in journalctl -u backup.timer heißt:
Der Timer hat nie etwas geplant. Beim Übersetzen aus einer Crontab hilft die
Zeitplan-Referenz — übersetzen Sie die Bedeutung, nicht die
Syntax.
Timer verwenden außerdem standardmäßig die System-Zeitzone (anders als GitHub Actions oder Vercel, die UTC erzwingen) — relevant, wenn eine auf dem Laptop geschriebene Unit auf einen UTC-Server deployt wird.
4. Der Timer hat ausgelöst — aber der Service schlug fehl
Ein aktuelles LAST in list-timers beweist nur, dass der Timer
funktioniert. Die Arbeit passiert in der zugehörigen Service-Unit
(backup.timer → backup.service, außer Unit= zeigt woanders hin):
systemctl status backup.service # Result: exit-code? oom-kill?
journalctl -u backup.service -n 50 # die eigentliche Ausgabe und Fehler
Die üblichen Verdächtigen, nach Häufigkeit:
- Relative Pfade — Units laufen von
/, nicht aus Ihrem Home. Absolute Pfade inExecStartund für jede Datei, die das Skript anfasst. - Fehlende Umgebung — Ihr Shell-Profil wird nicht geladen.
PATHist minimal;nvm-,pyenv-, rbenv-Shims und exportierte Secrets existieren nicht.Environment=/EnvironmentFile=in der Unit setzen. - Berechtigungen — der Service läuft als
User=(Standard: root bei System-Units); Dateien Ihres interaktiven Users sind evtl. nicht les-/schreibbar. Type=-Mismatch — ein Skript, das mitType=oneshotdaemonisiert (oder umgekehrt), lässt systemd den Prozess killen oder falsch verfolgen.
5. User-Timer stoppen beim Logout
Ein mit systemctl --user installierter Timer läuft nur, solange Sie eine
Session haben — außer Lingering ist aktiviert:
loginctl enable-linger $USER
Ohne stirbt Ihr Timer beim Logout und läuft erst beim nächsten Login weiter — das sieht exakt aus wie „stoppt zufällig“.
Außerdem gut zu wissen:
Persistent=trueholt einen verpassten Zeitplan beim nächsten Boot nach — essenziell für Maschinen, die nicht durchlaufen. Ohne überspringt ein 03:00-Timer auf einem schlafenden Laptop einfach.AccuracySecist standardmäßig 1 Minute, undRandomizedDelaySecfügt Jitter hinzu — beide lassen Läufe später als die wörtlicheOnCalendar-Zeit starten. Für PünktlichkeitAccuracySec=1s.WakeSystem=truekann eine schlafende Maschine für den Timer wecken — Standard ist, bis zum nächsten Aufwachen zu warten.
Das eigentliche Problem: Das Journal ruft Sie nicht an
Alles oben landet in journalctl — genau dort, wo niemand hinschaut, bis etwas
wochenlang kaputt war. Ein Timer, der aufhört zu planen, ein Service, der zu
scheitern beginnt, eine Maschine, die zur Triggerzeit aus war: alles still.
Schließen Sie die Lücke mit einem Heartbeat-Ping bei Erfolg:
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
ExecStartPost=/usr/bin/curl -fsS https://ping.steadycron.com/<ihr-ping-token>
ExecStartPost läuft nur, wenn ExecStart erfolgreich war — ein
fehlgeschlagenes Backup, ein toter Timer und eine ausgeschaltete Maschine
erzeugen also dasselbe Signal: einen ausgebliebenen Ping und einen Alarm per
E-Mail, Slack, Discord oder Telegram innerhalb Ihrer Grace-Zeit. Siehe
Heartbeat-Monitoring für Grace-Zeiten und
Alert-Routing sowie Ping-Snippets für
Wrapper-Muster, die auch Fehler melden (inklusive OnFailure=-Handler).
Häufige Fragen
Warum löst mein systemd-Timer überhaupt nicht aus?
Prüfen Sie die Grundlagen der Reihe nach: Ist der Timer aktiviert und gestartet (systemctl list-timers --all — zeigt NEXT eine Zeit?), haben Sie nach dem Editieren daemon-reload ausgeführt, und akzeptiert systemd-analyze calendar Ihren OnCalendar-Ausdruck? Ein NEXT von n/a bedeutet fast immer ein Kalender-Syntaxproblem.
Kann ich Cron-Syntax wie 0 3 * * * in OnCalendar verwenden?
Nein — OnCalendar ist kein Cron. Das Format ist Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde, z. B. *-*-* 03:00:00 für täglich um 03:00. Validieren mit systemd-analyze calendar "Ausdruck" — das zeigt auch die nächste Auslösung.
Warum zeigt mein Timer einen LAST-Lauf, aber nichts ist passiert?
Timer und Arbeit sind getrennte Units. LAST beweist nur, dass der Timer ausgelöst hat; die eigentliche Arbeit steckt in der zugehörigen Service-Unit. Prüfen Sie systemctl status ihrjob.service und journalctl -u ihrjob.service — vermutlich schlug der Service fehl (Pfade, Umgebung, Berechtigungen).
Warum stoppt mein systemd --user-Timer beim Logout?
User-Timer laufen nur mit aktiver Session, außer Lingering ist aktiviert: loginctl enable-linger $USER. Ohne stirbt der Timer beim Logout und läuft erst beim nächsten Login weiter — das sieht aus wie zufälliges Stoppen.
Warum läuft mein systemd-Timer jeden Tag zu leicht anderer Zeit?
AccuracySec ist standardmäßig 1 Minute und RandomizedDelaySec fügt bewussten Jitter hinzu — beide lassen Läufe nach der wörtlichen OnCalendar-Zeit starten. Für Präzision AccuracySec=1s setzen; Jitter behalten, wenn viele Maschinen denselben Zeitplan feuern.