8 Punkte von GN⁺ 2026-06-02 | 2 Kommentare | Auf WhatsApp teilen
  • systemd-Timer sind ein praktischer Ersatz für cron: Sie führen Units wie .service nach Zeitplan aus und machen Verlauf, Ausgabe und Umgebungsverwaltung klarer nachvollziehbar.
  • Traditionelles cron hat Schwächen wie ein mehrdeutiges $PATH, leicht verlorenes stdout/stderr, schwer nachzuverfolgende Ausführungshistorien und eine schlecht lesbare Zeitplan-Syntax.
  • Timer verknüpfen eine .timer- und .service-Datei mit demselben Stammnamen und drücken zeit- oder ereignisbasierte Ausführung mit OnCalendar, OnBootSec und OnUnitActiveSec aus.
  • Mit systemd-analyze calendar und systemctl list-timers lassen sich Zeitangaben und der nächste Ausführungszeitpunkt prüfen; WakeSystem= kann die Ausführung sogar aus dem Ruhezustand heraus aufwecken.
  • RandomizedOffsetSec und FixedRandomDelay= reduzieren gleichzeitige Lastspitzen, und Persistent= holt verpasste Läufe direkt nach dem Wieder-Online-Gehen nach.

Warum man systemd-Timer als Ersatz für cron verwendet

  • Der Begriff cron job wird allgemein verwendet, um einen grundlegenden Computing-Baustein zu bezeichnen, der Aufgaben nach einem Zeitplan ausführt — etwa „führe das jeden Tag aus“ oder „führe jenes jeden Monat aus“ — auch wenn nicht der eigentliche cron-Daemon dahintersteht.
  • Ein systemd-Timer ist eine systemd-Unit, die nach einem bestimmten Zeitplan eine andere Unit ausführt, meist eine .service, und kann ein funktionaler Ersatz für den traditionellen cron-Daemon sein.
  • Traditionelles cron hat einige praktische Schwächen:
    • Wegen einer mehrdeutigen $PATH-Konfiguration ist das Ergebnis der Skriptausführung schwer vorherzusagen.
    • stdout- und stderr-Ausgaben verschwinden oft im Nirgendwo oder werden an das Mailsystem des Hosts geschickt.
    • Die Ausführungshistorie ist schwer nachzuverfolgen und abzufragen.
    • Eine Zeitplan-Syntax wie 01,31 04,05 1-15 1,6 * ist für Menschen weder gut lesbar noch intuitiv.
  • systemd-Timer mindern diese Probleme und bieten zugleich Kalendereinstellungen, die cron-artigen Ausdrücken ähneln.

Grundstruktur: Service und Timer

  • Ein systemd-Timer braucht ein Ausführungsziel, und eine .service-Unit kann logisch wie ein Skript betrachtet werden.
  • Legt man zum Beispiel unter /etc/systemd/system/roulette.service die folgende Unit ab, installiert man einen Service, der den Computer mit einer Wahrscheinlichkeit von eins zu zehn herunterfährt.
[Unit]
Description=1 in 10 chance to break your chains

[Service]
ExecStart=/usr/bin/env bash -c '[[ $(($RANDOM % 10)) == 0 ]] && systemctl poweroff || echo LIVE ANOTHER DAY'
  • ExecCondition= ist eine stärker integrierte Art, bedingte Ausführung als systemd-Service-Option auszudrücken, und macht auf Unit-Ebene klarer sichtbar: „Soll weiter ausgeführt werden?“
[Unit]
Description=1 in 10 chance to break your chains

[Service]
ExecCondition=/run/current-system/sw/bin/bash -c '[[ $(($RANDOM % 10)) == 0 ]]'
ExecStart=/run/current-system/sw/bin/systemctl poweroff
  • Wenn die Bedingung nicht erfüllt ist, erscheint im Journal eine klarere Meldung.
May 05 11:05:32 diesel systemd[3117]: Condition check resulted in 1 in 10 chance to break your chains being skipped.
  • Generell ist es oft angenehmer, die von systemd bereitgestellten Optionen zu nutzen, statt selbst zu skripten.
    • OnFailure= kann verwendet werden, um auf fehlschlagende Service-Skripte zu reagieren.
    • Restart= kann verwendet werden, um bei vorübergehenden Fehlern eine Wiederherstellung zu versuchen.

Verknüpfen und Ausführen von Timer-Units

  • Legt man /etc/systemd/system/roulette.timer mit demselben Dateistamm an, kann man den Timer mit roulette.service verknüpfen.
[Unit]
Description=impending destruction

[Timer]
OnCalendar=10:00

[Install]
WantedBy=timers.target
  • Standardmäßig wählt die Unit=-Einstellung des Timers die Service-Unit mit demselben Stammnamen und der Endung .service.
    • In diesem Beispiel wird roulette.service gewählt.
    • Soll eine Service-Unit mit anderem Namen ausgeführt werden, kann Unit= geändert werden.
  • Das Ziel von ExecStart= wird standardmäßig nicht als Shell-Befehl ausgeführt.
    • Ein Ziel mit absolutem Pfad muss als Skript oder als Interpreter behandelt werden, der ein Skript als String-Argument erwartet.
    • ExecStart=/usr/bin/echo Hello | /usr/bin/awk funktioniert in diesem Kontext nicht, weil die Pipe hier keine Bedeutung hat.
  • ExecStart=-Argumente erben standardmäßig keine Umgebungsvariablen außer einigen Vorgaben des Systemmanagers.
    • Das Standard-$PATH ist fast leer.
    • Das Ausführen von /usr/bin/env ist eine einfache Schutzmaßnahme, damit Dinge wie systemctl verfügbar sind.
    • Selbst wenn ExecStart=/usr/bin/bash allein ein Standard-$PATH mitbringen würde, ist die Verwendung von env eine zusätzliche Absicherung.
  • Ein Service kann auch direkt ohne Timer ausgeführt werden.
systemctl start roulette
  • Ein Service ohne [Install]-Abschnitt kann nicht mit enable aktiviert werden; in dieser Struktur ist der Timer der Standardweg, um den Service konsistent auszuführen.
  • systemctl arbeitet standardmäßig mit roulette.service, auch wenn kein explizites Suffix angegeben wird.
  • Wenn man systemctl start auf eine .timer-Unit anwendet, wird der Timer aktiv, aber der eigentliche mit Unit= angegebene Service wird nicht sofort ausgeführt.
systemctl start roulette.timer
  • status zeigt an, wann der Timer das nächste Mal ausführt.
systemctl status roulette.timer
Trigger: Sat 2026-04-18 10:00:00 MDT; 35min left
  • Der einfachste Ablauf ist: den auszuführenden Service anlegen, einen Timer mit Zeitplan am selben Ort ablegen und dann den Timer statt des Ziels starten.
  • Wenn der [Install]-Abschnitt der Timer-Unit WantedBy= enthält, kann der Timer auch beim Booten automatisch hochkommen.
systemctl enable roulette.timer

Zeitausdrücke: Kalenderereignisse und Zeitspannen

  • Bei Timern ist wichtig, wie Zeitpläne ausgedrückt werden: Man sollte zwischen wiederkehrenden Zeitintervallen und Kalenderereignissen oder Zeitstempeln unterscheiden.
  • Die Handbuchseite systemd.time(7) enthält genügend Beispiele und ist eine gute erste Referenz beim Schreiben von Timern.
  • systemd-analyze kann Zeitausdrücke prüfen und erläutern.
systemd-analyze calendar '*-*-* *:*:*'
Normalized form: *-*-* *:*:*
    Next elapse: Sat 2026-04-18 16:44:26 MDT
       (in UTC): Sat 2026-04-18 22:44:26 UTC
       From now: 431ms left
  • systemd-Timer können nicht nur wiederkehrende Wanduhrzeiten definieren, sondern im Unterschied zu traditionellem cron auch wiederkehrende Zeitspannen relativ zu einem früheren Ereignis.
  • Die vollständige Form von daily bedeutet: jedes Jahr, jeden Monat, jeden Tag um 00:00:00 ausführen.
*-*-* 00:00:00
│ │ │ │  │  ╰── at second 00
│ │ │ │  ╰───── at minute 00
│ │ │ ╰──────── at hour 00
│ │ ╰────────── every day
│ ╰──────────── every month
╰────────────── every year
  • Man kann Kurzformen wie daily, die vollständige Form und andere von systemd.time(7) unterstützte Werte verwenden und seine Annahmen mit systemd-analyze überprüfen.

Wenn ereignisbasierte Ausführung besser passt

  • In der Praxis passt „nach einem anderen Ereignis ausführen“ oft besser als „jeden Tag zur gleichen Uhrzeit ausführen“.
  • Beim Leeren eines temporären Verzeichnisses gibt es in /tmp kurz nach dem Booten vielleicht kaum etwas aufzuräumen, wenn der cron-Zeitpunkt bereits verstrichen ist.
  • Die Formulierung „eine Stunde nach dem Start des Computers ausführen und danach stündlich“ passt oft besser zum tatsächlichen Verhalten des Services und zur Logik des Zeitplans.
[Timer]
OnBootSec=1h
OnUnitActiveSec=1h
  • OnBootSec=1h bedeutet: einmal eine Stunde nach dem Start der Maschine ausführen.
  • OnUnitActiveSec=1h bedeutet: eine Stunde nach der Ausführung von Unit= erneut ausführen, wodurch der Timer implizit dauerhaft wiederholt wird.
  • Solche periodischen Zeitspannen passen häufiger zu „ab und zu mal ausführen“ als Ausdrücke wie „jede Stunde zu dieser Minute“.
  • Beim Beispiel eines Slack-Bots, der die Advent of Code-API pollt, hält der cron-Ausdruck */15 zwar die Richtlinie „alle 15 Minuten“ der API ein, aber wenn alle auf dieselbe Weise pollen, kann sich der Traffic ballen.
  • Wenn man nach einer Codeänderung den Timer startet und ihn dann jeweils 15 Minuten später ausführen lässt, erfüllt man das gewünschte Verhalten und reduziert womöglich das thundering herd-Problem.

Timer-Status auf einen Blick

  • systemctl list-timers ist ein High-Level-Befehl, der die Timer-Situation auf einem System zusammenfasst.
systemctl list-timers
NEXT                                 LEFT LAST                                  PASSED UNIT                         ACTIVATES
Mon 2026-04-20 15:15:00 MDT      1min 40s Mon 2026-04-20 15:00:05 MDT        13min ago zfs-snapshot-frequent.timer  zfs-snapshot-frequent.service
Mon 2026-04-20 15:32:16 MDT         18min Mon 2026-04-20 14:22:15 MDT        51min ago fwupd-refresh.timer          fwupd-refresh.service
Mon 2026-04-20 16:00:00 MDT         46min Mon 2026-04-20 15:00:05 MDT        13min ago logrotate.timer              logrotate.service
Mon 2026-04-20 16:00:00 MDT         46min Mon 2026-04-20 15:00:05 MDT        13min ago zfs-snapshot-hourly.timer    zfs-snapshot-hourly.service
Tue 2026-04-21 00:00:00 MDT            8h Mon 2026-04-20 09:43:22 MDT     5h 29min ago zfs-snapshot-daily.timer     zfs-snapshot-daily.service
Tue 2026-04-21 07:31:28 MDT           16h Sun 2026-04-19 20:15:47 MDT           7h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Mon 2026-04-27 00:00:00 MDT        6 days Mon 2026-04-20 09:43:22 MDT     5h 29min ago zfs-snapshot-weekly.timer    zfs-snapshot-weekly.service
Mon 2026-04-27 01:09:27 MDT        6 days Mon 2026-04-20 09:43:22 MDT     5h 29min ago fstrim.timer                 fstrim.service
Mon 2026-04-27 04:28:38 MDT        6 days Mon 2026-04-20 09:43:22 MDT     5h 29min ago zpool-trim.timer             zpool-trim.service
Fri 2026-05-01 00:00:00 MDT 1 week 3 days Wed 2026-04-01 10:07:51 MDT 1 week 1 day ago zfs-snapshot-monthly.timer   zfs-snapshot-monthly.service
Fri 2026-05-01 03:17:17 MDT 1 week 3 days Wed 2026-04-01 10:07:51 MDT 1 week 1 day ago zfs-scrub.timer              zfs-scrub.service

11 timers listed.
Pass --all to see loaded but inactive timers, too.
  • Mit einem einzigen Befehl erhält man einen Gesamtüberblick über alle Elemente, die nach Timer-Zeitplänen laufen.
  • list-timers gehört zu einer häufig genutzten Familie von systemd-Unterbefehlen.
    • list-units ist ebenfalls nützlich.
    • list-paths ist ein neuerer Unterbefehl, der systemctl hinzugefügt wurde.

Aus dem Ruhezustand aufwecken und ausführen

  • WakeSystem= kann dafür sorgen, dass ein abgelaufener Timer das System aus dem Ruhezustand aufweckt.
WakeSystem=
    Takes a boolean argument. If true, an elapsing timer will
    cause the system to resume from suspend, should it be
    suspended and if the system supports this.
...
  • Das ist nützlich, wenn ein wichtiges Skript laufen soll, ohne dass jemand physisch den Laptopdeckel öffnen muss.
  • Auf Distributionen wie Arch oder NixOS, die das Herunterladen von Paket-Updates vor der eigentlichen Nutzung unterstützen, kann man spät nachts Update-Pakete vorab holen und sie morgens an der Tastatur installieren.
  • Laut Handbuch muss man das erneute Versetzen in den Ruhezustand manuell veranlassen, wenn das System nach Abschluss der .service wieder schlafen soll.

Ausführungszeiten streuen und thundering herd entschärfen

  • Das thundering herd-Problem ist ein Systemproblem, das auftritt, wenn viele Prozesse gleichzeitig aufwachen.
  • Wenn weltweit alle Debian-Systeme hart auf 00:00:00 für apt update eingestellt wären, wäre Mitternacht für alle eine schlechte Traffic-Spitzenzeit.
  • FixedRandomDelay= und RandomizedOffsetSec= helfen dabei, Ausführungszeiten zu verteilen.
FixedRandomDelay=
    Takes a boolean argument. When enabled, the randomized delay
    specified by RandomizedDelaySec= is chosen deterministically,
    and remains stable between all firings of the same timer,
    even if the manager is restarted. ...

RandomizedOffsetSec=
    Offsets the timer by a stable, randomly-selected, and evenly
    distributed amount of time between 0 and the specified time
    value. ...
  • Solche Einstellungen können auf realen Systemen verwendet werden, die nach Software-Updates suchen.
  • Eine gleichmäßige Verteilung der Ausführung hilft, das thundering herd-Problem zu reduzieren, das Verhalten konsistent zu halten und Störungen wie Daemon-Neustarts während der Koordination verteilter Dienste zu vermeiden.
  • Insgesamt sind die Timing-Optionen sehr gut konfigurierbar und bieten feingranulare Kontrolle.

Verpasste Ausführungen sofort nachholen

  • Persistent= eignet sich besonders für geplante Skripte, die wegen eines schlafenden Laptops nicht verpasst werden sollten, für die aber WakeSystem= nicht nötig ist.
Persistent=
    Takes a boolean argument. If true, the time when the service
    unit was last triggered is stored on disk. When the timer is
    activated, the service unit is triggered immediately if it
    would have been triggered at least once during the time when
    the timer was inactive. ...
  • Wenn ein für Konfigurationsmanagement geplantes Check-in-System Ausfallzeit hatte, kann schon Persistent= in der .timer genügen, damit es direkt nach dem Wieder-Online-Gehen in den richtigen Zustand konvergiert.
  • Ohne Persistent= muss man womöglich bis zum nächsten regulären Ausführungszeitpunkt des Timers warten, und das kann lange dauern.
  • Weitere Aufgaben, bei denen man bei erkannter verpasster Aktivierung nicht warten sollte, sind System-Updates oder die Prüfung von Batch-Jobs.

Worauf man beim Schreiben von Timern achten sollte

  • Timer im Kontext des Benutzer-Managers, die mit systemctl --user verwaltet werden, sind ebenfalls sinnvoll, aber man sollte auf das Ziel im [Install]-Abschnitt achten.
  • Je nach Distribution kann für Benutzer-Timer default.target das passende Ziel sein.
  • Wie bei cron gilt weiterhin der allgemeine Hinweis, dass eine korrekte Systemzeit wichtig ist.
  • systemd-Nutzer können den Synchronisationsstatus mit timedatectl timesync-status prüfen.
  • Viele Editoren unterstützen das Format von systemd-Unit-Dateien direkt, was bei größeren Unit-Dateien hilfreich ist.
  • In Emacs kann man das Paket emacs systemd verwenden.

2 Kommentare

 
GN⁺ 2026-06-02
Hacker-News-Kommentare
  • Ich habe systemd-Timer nicht oft genug verwendet, um dem entschieden zu widersprechen, aber die Aussage, dass $PATH bei cron unklar ist, verstehe ich nicht so recht.
    Man kann PATH direkt in der crontab setzen; ich sehe nicht, warum das unvorhersehbarer sein soll als Einstellungen in /etc/bashrc, ~/.bashrc, ~/.profile, ~/.bash_profile oder /etc/systemd/….
    Ich nutze Linux seit 1994, habe mir aber die cron-Syntax nicht auswendig gemerkt. In den Kommentaren der crontab steht jedoch schon m h dom mon dow command, also muss man nur passend zu den Bezeichnungen die Zahlen eintragen.
    Die übrigen Beschwerden kann ich nachvollziehen, und wenn ich das nächste Mal einen cron-Job brauche, werde ich wohl einmal systemd-Timer ausprobieren.

    • „Man muss nur passend zu den Bezeichnungen die Zahlen eintragen“ ist keine faire Zusammenfassung der ursprünglichen Kritik, denn das ist nicht die ganze Syntax.
      Es gibt Kommas, Schrägstriche, Sternchen und Kombinationen davon, und wenn man Randomisierung braucht, geht das mit cron selbst normalerweise nicht, sodass man sie in den Befehl einbauen muss. Eine nichttriviale cron-Spezifikation zu schreiben ist nicht einfach.
    • Aus der Perspektive von jemandem, der mit Anwendungen gearbeitet hat, die cron-Ausdrücke unterstützen, sind Zahlen nur der elementarste Teil der Sprache.
      Wenn jemand etwas wie 5,3/4 4-8,11 1 4,5,6,9-11 */2 einträgt, beginnt der Spaß des Reverse Engineerings, was eigentlich gemeint war — und meist ist es nicht das, was tatsächlich geschrieben wurde.
      Mit Erweiterungen, die nur in manchen cron-Umgebungen unterstützt werden, wird es noch komplizierter.
      systemd-Timer waren deutlich angenehmer zu verwalten. Die Kontrolle darüber, ob lang laufende Jobs mehrfach parallel laufen dürfen, oder die Möglichkeit, Jobs innerhalb eines Start-Ende-Fensters statt zu einer festen Uhrzeit auszuführen, sind große Verbesserungen.
      Früher ist einmal ein Backup-Job in eine Symlink-Schleife geraten und hat meinen VPS lahmgelegt; cron startete trotzdem immer wieder neue Backup-Jobs, obwohl das vorige noch nicht beendet war.
      Dass ich wegen des speziellen PATH von CRON Befehle und Skripte umschreiben musste, war ebenfalls lästig, auch wenn das bei manchen systemd-Timern ähnlich sein kann. Trotzdem kann man einen Timer manuell starten, ohne die crontab erst auf „in 30 Sekunden“ umzubiegen und dann zu warten.
    • Ich möchte zum Testen von cron-Jobs $PATH nicht in die crontab hartcodieren.
      Wenn ich es nicht hartcodiere, ist der $PATH, mit dem cron etwas ausführt, anders als der $PATH, den ich beim direkten Testen des Befehls habe. systemctl start foo.service startet den Befehl in derselben Umgebung, die auch beim Auslösen des Timers verwendet wird, daher kann ich erkennen, ob er sich gleich verhält.
      Dagegen laufen cron-Jobs einfach zu der in der crontab angegebenen Zeit. systemd-Timer lösen zwar meist zur angegebenen Zeit aus, können aber wegen Logik-Bugs in systemd nach einer einmaligen Ausführung am 29. Februar nie wieder laufen oder beim „restart“ einer Timer-Unit vielleicht auslösen und vielleicht auch nicht.
    • Der Vorteil der systemd-Umgebung ist, dass sie standardisiert und fast leer ist. Die crontab-Umgebung dagegen unterscheidet sich vollständig von der Umgebung, die supervisord- oder sysvinit-Skripte erben, und damit bin ich schon oft auf die Nase gefallen.
      Bei systemd ist die tatsächlich ausgeführte Unit dieselbe, egal was sie auslöst, daher gibt es diese Lücke nicht.
      Man muss zwar immer noch wissen, was die Standardumgebung ist, aber es ist eine nahezu saubere Umgebung, unbeeinflusst von der Shell. Das sehe ich als Vorteil von systemd.
    • Ich würde nicht sagen, dass PATH völlig unklar ist, aber cron hat durchaus PATH-Probleme.
      In den Standardwerten fehlen oft Dinge, die man erwarten würde, etwa /usr/local/bin oder /usr/sbin für root, und einige Distributionen wie Arch Linux erwähnen in den Manpages weder den Standardpfad noch empfohlene Einstellungen.
      Wenn man den Pfad nur für ein bestimmtes Skript erweitern will, muss man mit env arbeiten, es in einem Wrapper-Skript setzen oder den Pfad vor einem Eintrag ändern und danach wieder zurücksetzen.
      Man kann in PATH weder ~ noch $HOME verwenden und muss absolute Pfade ausschreiben, was besonders in Benutzer-crontabs lästig ist.
      Das ist zwar kein schwer zu umgehendes Problem, aber systemd-Timer, die standardmäßig denselben Pfad wie andere Dienste nutzen, bieten aus meiner Sicht die bessere Erfahrung.
  • Ich bin von cronie auf systemd-Timer umgestiegen, weil sie gegenüber der Systemstartzeit robuster sind.
    Meine Backup-Strategie erstellt jeden Tag zu einer festen Zeit einen borg-Archiv-Eintrag, aber bei cronie muss das System zum geplanten Zeitpunkt eingeschaltet sein. systemd-Timer halten diesen Fall aus und führen den Dienst aus, sobald das System verfügbar ist.
    Das Repository für die Backup-Automatisierung ist https://github.com/gchamon/borg-automated-backups.

    • Cronie hat dafür einen Mechanismus namens anacron. Auf meinem System ruft cron stündlich /etc/cron.hourly/0anacron auf und führt dann Jobs aus /etc/cron.{daily,weekly,monthly} aus, auch wenn die früheste Ausführungszeit verpasst wurde. Eine zufällige Verzögerung lässt sich ebenfalls konfigurieren.
      Wenn man /etc/anacrontab bearbeitet, kann man eigene Zeitpläne erstellen.
      Auf Benutzerebene könnte man wohl einen Eintrag wie @hourly anacron -t /path/to/anacrontab -S /path/to/spooldir in die Benutzer-crontab setzen, ausprobiert habe ich das aber nicht.
      Viele cron-Implementierungen haben ähnliche Mechanismen.
    • cron hat die Option @reboot, und ich nutze sie in einigen Skripten; sie funktioniert gut.
    • Hat Cronie keinen Meta-Trigger @reboot?
  • Canon-Druckerdüsen können verstopfen, wenn sie eine Weile unbenutzt bleiben, deshalb traue ich ihnen nicht. Also habe ich Claude ein systemd-Skript erstellen lassen, das jede Woche Hundefotos ausdruckt, und dafür gesorgt, dass genug vom CMYK-Spektrum enthalten ist, damit der Drucker ordentlich beschäftigt wird
    Es ist jedes Mal eine ziemlich angenehme Überraschung, wenn ich mich montags an den Schreibtisch setze und plötzlich ein Foto aus dem Drucker kommt

    • Es wäre schön, wenn Drucker statt alle paar Tage Tinte in einen Schwamm zu spülen einfach einen Modus hätten, der zufällige Bilder aus einem Album oder Kalender druckt
      Das wäre zumindest eine mögliche Idee für ein Wissenschaftsprojekt der Kinder
    • Mein Vater hatte ein Modell ähnlich dem Deskjet 720
      Nach seinem Tod stand es ein paar Jahre ausgeschaltet und unbenutzt herum, aber ich brauchte einen Farbausdruck, habe nur den Strom angeschlossen und gedruckt
      Nach etwa 1/5 der ersten Seite waren alle Farben wieder da, und danach hat es rund 20 Seiten problemlos gedruckt
    • In meinen ersten Uni-Jahren habe ich mit einem alten Samsung ML-2010 etwas Ähnliches gemacht
      Es wirkte eher wie ein Software- als ein Hardwareproblem: Wenn der Drucker länger als eine Woche am Rechner hing und nichts tat, hörte er einfach auf zu drucken
      Ich hätte mich durch die Logs wühlen können, aber stattdessen habe ich einen cron-Job eingerichtet, der montags und donnerstags eine Testseite druckte. Oben auf der Testseite stand nur etwas wie LOL PRINTER WORKS
      So verschwenderisch war das gar nicht. Ich hatte viele Mathekurse und brauchte massenhaft Schmierpapier für Rechenwege; zuerst habe ich Fehldrucke oder Testdrucke benutzt und erst danach leere Blätter
    • Die Antwort ist ein Laserdrucker. Allein durch die Ersparnis bei den Verbrauchsmaterialien lohnt sich das
    • Ich wollte einen günstigen OKI-LED-Farbdrucker empfehlen, aber sie haben sich aus dem Consumer-Markt zurückgezogen
      Die maximale Auflösung lag zwar nur bei 600dpi, aber die Farben waren sehr gut und gleichmäßig, und dass Toner nicht austrocknet, war für meinen Bruder das wichtigste Kaufkriterium. HP-Tintenstrahldrucker sind ihm mehrfach eingetrocknet
  • Ich mag systemd-Timer sehr. Ich habe nach und nach alle cron-Jobs, die ich mit Ansible ausgerollt hatte, auf Timer umgestellt, und jetzt muss Ansible sie nur noch kopieren
    Besonders gut ist die Integration mit journalctl, und auf neueren OS ohne syslog wie Debian 13 ist das noch besser. Praktisch ist auch, dass man den Service zum Debuggen manuell starten kann
    Nicht funktionierende cron-Jobs waren immer ein Ärgernis, bei dem man Dinge zusammenkopieren oder zusätzliche Shell-Skripte schreiben musste, ganz zu schweigen vom schwarzen Loch, in dem die Standardausgabe von cron-Jobs verschwindet
    Man kann systemd-Services wie bisher überwachen und Benachrichtigungen bei Fehlern bekommen. Ich finde es auch gut, dass Open-Source-Projekte Timer zunehmend als Deployment-Methode empfehlen

    • Damit ein Projekt Timer empfiehlt, habe ich kein Problem, aber ich bin nur zufrieden, wenn ich das ignorieren und cron verwenden kann
  • NixOS setzt standardmäßig auf systemd und nutzt es als erstklassigen Bestandteil der Verwaltung. Besonders gut ist das, wenn man von macOS mit launchd kommt
    Schön ist auch, dass man beim Verteilen von Tools für NixOS systemd natürlich nutzen kann, statt es nachträglich als Behelf dranzuflicken
    Wenn man allerdings ein Tool mit viel Lifecycle-Management für alle Linux-Nutzer ausliefern will, frage ich mich, was man tun soll, weil systemd eben nicht überall vorhanden ist
    Ich lasse den monatlichen Scrub meines btrfs-Pools über einen systemd-Timer laufen. Es ist ziemlich nützlich, dass man festlegen kann, ob der nächste geplante Lauf übersprungen wird, wenn der Benutzer selbst einen Scrub startet, oder ob sich Jobs aufstauen bzw. zu einem einzelnen Lauf zusammengefasst werden, wenn ein monatlicher Job geplant ist, das Gerät aber 6 Monate ausgeschaltet war

    • Unter NixOS sind systemd-Jobs wirklich einfach. Units in Nix zu definieren ist besser, als mit INI-Dateien zu ringen
      systemd.services.sync-recyclarr = { serviceConfig.Type = "oneshot"; path = [ pkgs.podman ]; script = '' podman exec -it recyclarr recyclarr sync radarr podman exec -it recyclarr recyclarr sync sonarr ''; };
      systemd.timers.sync-recyclarr = { timerConfig = { OnCalendar = "daily"; Persistent = true; Unit = "sync-recyclarr.service"; }; partOf = [ "sync-recyclarr.service" ]; requires = [ "podman-recyclarr.service" ]; wantedBy = [ "timers.target" ]; };
    • Ich frage mich, ob du das direkt in der flake.nix-Datei definierst
      Ich nutze auch NixOS, halte meine Konfigurationen aber alle im ursprünglichen Format und lasse Nix nur symbolische Links darauf setzen. So kann ich die Konfiguration auch auf Nicht-NixOS-Systemen leicht wiederverwenden
      Das Problem ist, dass NixOS anscheinend systemd-Timer und -Services aus dem Ordner ~/.config/systems/user nicht aufgreift und startet, und Dinge wie WantedBy=default.target scheinen auch keine Wirkung zu haben
      Deshalb stimme ich erst dann zu, dass systemd-Timer großartig sind, nachdem ich nach einem Neustart alle Services manuell neu gestartet habe
  • Timer funktionieren überraschend flexibel nicht nur mit Service-Units gleichen Namens, sondern auch mit beliebigen anderen Units
    Auf meinem Server gibt es einen Timer, der jeden Morgen mit zufälliger Startzeit und Benachrichtigung backup.target startet, das den gesamten Backup-Zyklus mit restic backup, restic prune und restic forget ausführt
    Die eigentlichen restic-*-Units sind Podman-Quadlets, daher funktioniert die Konfiguration unabhängig vom Serverinhalt, solange nur Podman und Systemd vorhanden sind
    Allerdings gehören Timer zu den sperrigsten systemd-Unit-Typen für den täglichen Gebrauch. Ich verstehe, warum sie in zwei Dateien aufgeteilt sind und warum sich die Syntax für start und enable unterscheidet, aber manchmal möchte ich einfach nur eine Datei erstellen, ein Skript ausführen und fertig

    • Für Backups nutze ich eine ähnliche Konfiguration. Ich habe den Timer gelegentlich deaktiviert, weil ich im restic-Repository andere Arbeiten wie das Aufräumen von Sperren machen wollte, und wurde dann davon überrascht, dass bereits ausgelöste Units trotzdem noch liefen
    • Es wirkt, als bräuchte es noch eine Abstraktionsschicht über systemd-Units. Statt Dateien direkt zu bearbeiten, sollte das irgendein deklaratives Kommandozeilen-Tool übernehmen
      Im Zeitalter der LLMs ist das vielleicht kein großes Problem mehr, aber es fühlt sich jedes Mal ein bisschen umständlich an
    • Ich frage mich, warum du die Backup-Zeit zufällig machst
  • Ich mochte bestimmte Aspekte von systemd nie besonders, stimme diesem Eindruck aber größtenteils zu.
    Für geplante Aufgaben auf „System“-Ebene nutze ich inzwischen fast gar kein cron mehr und bevorzuge systemd-Timer. Für Scheduling im Rahmen einer bestimmten Anwendung kann man auch etwas wie Quartz einsetzen.
    Der Grund ist etwas vage und schwer zu erklären, aber der systemd-Ansatz passt sauberer zu meinem mentalen Modell davon, „wie so etwas funktionieren sollte“. Früher hatte ich auch öfter Fälle, in denen die PATH-Umgebung bei cron-Skripten unklar war und das Verhalten schwer vorhersehbar wurde, aber das ist nicht alles.
    Ich würde nicht behaupten, dass systemd-Timer universell und objektiv besser sind als cron, aber mich haben sie zumindest überzeugt.

  • Das war ein sehr guter Einstieg in systemd-Timer und überzeugend genug, dass ich sie jetzt endlich ausprobieren werde.
    list-timers gefällt mir auch. Bei cron war es nie einfach, sich auf einen Blick einen Überblick über alle Cronjobs auf einer Maschine zu verschaffen. Man musste die Crontabs aller Benutzer, /etc/cron.d/ sowie die daily/hourly/monthly-Verzeichnisse prüfen.
    Ich habe tatsächlich einen Anwendungsfall, der etwa 5 Minuten nach dem Booten einmal laufen und danach etwa alle 12 Stunden ausgeführt werden soll, und es ist schön, dass systemd-Timer das abdecken.

    • Danke für die netten Worte. In einer Welt, in der systemd heute so weit verbreitet ist, halte ich es wirklich für lohnend, den Umgang mit Werkzeugen wie systemd-analyze und systemctl list-timers zu lernen.
  • systemd wirkt am Anfang komplex, aber wenn man es erst einmal benutzt, möchte man nichts anderes mehr verwenden. Es ist bequem, alles mit systemctl zu verwalten.

    • Im Design gibt es immer noch seltsame Entscheidungen, die ich nicht vollständig verstehe.
      Zum Beispiel verstehe ich nicht, warum Unit-Definitionen zwingend echte Dateien auf der Festplatte sein müssen. Wenn der Daemon neu lädt, liest er nicht nur geänderte Dateien neu ein, sondern alle. Ich frage mich, warum es keine API gibt, mit der man Units programmatisch hinzufügen kann. Es gibt zwar etwas Ähnliches, aber das hat viele Einschränkungen und ist nicht flexibel.
      Dass man in einer Datei nicht mehrere Units deklarieren kann, finde ich ebenfalls fragwürdig. Die Entscheidung für ein dateisystemzentriertes Design ohne andere Abstraktionsebenen wirkt nicht besonders klug. Mit der Unix-Philosophie hat das auch nicht gerade viel zu tun.
      Auch beim Format der Unit-Definitionen denke ich, dass man etwas Vernünftigeres gewählt hätte, wenn es TOML damals schon gegeben hätte.
    • systemd hat tatsächlich Handbuchseiten, die nützlich sind.
    • Andere sehen das anders. Manche wollen es nach dem Ausprobieren gerade nicht mehr benutzen. Ich hasse systemd aus tiefstem Herzen.
      Klar, wahrscheinlich bin ich einfach alt. Natürlich ist nur systemd-* der einzig richtige Weg, und alle, die das anders sehen, sind bloß Besserwisser.
    • journald-Logging mag ich immer noch nicht.
    • Das ist eine ziemlich moderne Sichtweise. Als systemd neu aufkam, haben es die Leute wirklich gehasst, aber ich mochte es immer und dachte, am Ende würden es die Leute akzeptieren. Schön zu sehen, dass es jetzt tatsächlich so gekommen ist.
  • Ich nutze Linux seit über 20 Jahren und systemd seit über 10 Jahren.
    Trotzdem gibt es immer noch Neues zu lernen, und ich betrachte das tatsächlich wieder als ein weiteres nützliches Werkzeug.

    • Ich nutze Linux seit etwa 30 Jahren; offenbar haben wir also jahrzehntelang alle cron benutzt und lagen damit komplett falsch.
 
GN⁺ 2026-06-02
Lobste.rs-Meinungen
  • systemd ist zwar nicht perfekt, aber viele Designentscheidungen wirken so, als würden sie auf Erkenntnissen aus traditionelleren früheren Ansätzen beruhen
    Ich habe mir neulich noch einmal die Episode von CRE aus dem Jahr 2015 angehört, in der Lennart Poettering den Hintergrund erklärt, und kann sie immer noch empfehlen

  • Ich gehöre eher zur Fraktion, die systemd durch und durch nicht mag, aber systemd.timers halte ich für eines der „weniger schlechten“ Konzepte dieses Produkts
    Deshalb war ich etwas überrascht, dass der Autor es auf eine Weise verteidigt hat, die Leute mit berechtigten Beschwerden herabsetzt
    Trotzdem ist die Nutzung zusammen mit dem at-Befehl gut. Für Befehle, die einmal zu einem bestimmten Zeitpunkt ausgeführt werden sollen, nutze ich at, und für alles andere systemd-Timer mit einfachen Unit-Dateien
    Die Verbesserung, die ich am liebsten sehen würde, wäre, erkennen zu können, welcher Benutzer einen Timer ausführt. Ich bin zwar einer der wenigen Leute, die 2026 noch eine Shellbox betreiben, aber es wäre nützlich zu wissen, welcher Benutzer einen Timer eingerichtet hat, der jede Sekunde auf die Festplatte hämmert

    • Für diesen Zweck könnte man vielleicht Benutzer-Units verwenden, statt alle System-Timer installieren zu lassen
      Soweit ich weiß, kann es mit loginctl enable-linger auch ohne aktive Benutzersitzung laufen. Natürlich gibt es sicher Anwendungsfälle, für die das nicht ausreicht, aber ich kenne die konkrete Situation nicht
  • Bei systemd-Timern wäre es besonders auf der Seite der Benutzerverwaltung schön, wenn die Einstiegshürde niedriger wäre
    Wenn man sieht, wie viel Konfiguration nötig ist, ist crontab -e wirklich nur schwer zu schlagen

    • Der systemd-Ansatz, für einen einzelnen Timer mehrere Konfigurationsdateien und Dienste zu verlangen, ist als API-Entscheidung schon fast absurd
  • Ich habe lange darüber nachgedacht, wie man Logs von cron-Skripten systematisch sammeln kann, und dann gemerkt, dass man einfach systemd-Timer verwenden kann
    Das Logging-Problem ist damit gelöst. Jetzt habe ich keinen Grund mehr, wieder cron zu verwenden, und wünschte, ich hätte das früher gewusst

    • Kann man es nicht einfach mit logger weiterleiten oder mit >> an eine Logdatei anhängen oder die Standardeinstellung beibehalten und E-Mails empfangen?
  • Nennt es ruhig altmodisch, aber auf Servern richte ich mir immer noch E-Mail ein, die mich erreicht
    Wenn man das automatisiert, ist es auf jedem neuen Host kostenlos mit dabei, und auch im Alltag ziemlich praktisch
    Zum Beispiel öffne ich einen Multiplexer, führe long_running_process | mail root@localhost -s "done $?" aus und vergesse es dann einfach

  • Guter Artikel, und ich hatte selbst einen Entwurf für einen ähnlichen Artikel, auf den ich kürzlich wieder zurückgreifen musste
    Wenn man wie ich in den systemd-Kaninchenbau hinabsteigt, empfehle ich, die Unit-Dateien und Timer im zugehörigen Projektordner nach /etc/systemd/system/ symbolisch zu verlinken
    Eine meiner Beschwerden über systemd ist, dass es nicht zwischen von der Distribution installierten Units und selbst geschriebenen Units unterscheidet, aber mit symbolischen Links kann man diese Trennung selbst aufrechterhalten

    • Eigentlich übernimmt der Pfad diese Unterscheidung
      System-/Paket-/Distributions-Units liegen unter /usr/lib/systemd/system, und lokale Overrides oder lokale Units unter /etc/systemd/system