8 points par GN⁺ 2026-06-02 | 2 commentaires | Partager sur WhatsApp
  • Les timers systemd sont un remplaçant pragmatique de cron : ils exécutent des unités comme des .service selon un planning, tout en rendant l’historique, la sortie et la gestion de l’environnement plus explicites
  • Le cron traditionnel souffre de plusieurs faiblesses : un $PATH ambigu, des stdout/stderr faciles à perdre, un historique d’exécution difficile à suivre et une syntaxe de planification peu lisible
  • Les timers relient un .timer et un .service de même racine, et expriment des exécutions basées sur l’heure ou sur des événements avec OnCalendar, OnBootSec et OnUnitActiveSec
  • systemd-analyze calendar et systemctl list-timers permettent d’inspecter les expressions temporelles et la prochaine heure d’exécution, tandis que WakeSystem= peut réveiller la machine même depuis un état de veille
  • RandomizedOffsetSec et FixedRandomDelay= réduisent les pics d’exécution simultanée, et Persistent= rattrape juste après la reconnexion les exécutions manquées pendant l’inactivité

Pourquoi utiliser les timers systemd à la place de cron

  • L’expression cron job est largement utilisée pour désigner l’élément de base qui exécute des tâches selon un planning, comme « exécuter ceci tous les jours » ou « exécuter cela tous les mois », même lorsqu’il ne s’agit pas du démon cron lui-même
  • Un timer systemd est une unité systemd qui exécute une autre unité, généralement un .service, selon un planning donné, et peut servir de remplaçant fonctionnel au démon cron traditionnel
  • Le cron traditionnel présente plusieurs faiblesses en pratique
    • une configuration de $PATH ambiguë rend le résultat de l’exécution des scripts difficile à prévoir
    • les sorties stdout et stderr finissent souvent dans un trou noir ou sont envoyées au système de messagerie de l’hôte
    • il est difficile de suivre et d’interroger l’historique d’exécution
    • une syntaxe comme 01,31 04,05 1-15 1,6 * n’est ni facile à lire ni intuitive
  • Les timers systemd réduisent ces problèmes tout en proposant une configuration de calendrier proche des expressions de style cron

Structure de base : service et timer

  • Un timer systemd a besoin d’une cible à exécuter, et une unité .service peut logiquement être vue comme l’équivalent d’un script
  • Par exemple, placer l’unité suivante dans /etc/systemd/system/roulette.service installe un service qui éteint l’ordinateur avec une probabilité de 1 sur 10
[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= est une manière plus intégrée d’exprimer une exécution conditionnelle via les options de service systemd, et rend plus clairement au niveau de l’unité la question « faut-il continuer l’exécution ? »
[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
  • Si la condition n’est pas remplie, le journal laisse un message plus explicite
May 05 11:05:32 diesel systemd[3117]: Condition check resulted in 1 in 10 chance to break your chains being skipped.
  • En général, tirer parti des options fournies par systemd offre une meilleure expérience que d’écrire soi-même des scripts
    • OnFailure= peut être utilisé pour réagir à l’échec d’un script de service
    • Restart= peut être utilisé pour tenter une récupération après un échec temporaire

Associer une unité timer et l’exécuter

  • En plaçant un /etc/systemd/system/roulette.timer avec la même racine, on peut relier le timer à roulette.service
[Unit]
Description=impending destruction

[Timer]
OnCalendar=10:00

[Install]
WantedBy=timers.target
  • Par défaut, le paramètre Unit= d’un timer sélectionne l’unité de service portant la même racine, avec le suffixe .service
    • dans cet exemple, c’est roulette.service qui est sélectionné
    • pour exécuter une unité de service d’un autre nom, on peut modifier Unit=
  • La cible de ExecStart= n’est pas exécutée comme une commande shell par défaut
    • une cible avec chemin absolu doit être traitée comme un script, ou comme un interpréteur attendant un script sous forme de chaîne d’arguments
    • ExecStart=/usr/bin/echo Hello | /usr/bin/awk ne fonctionnera pas dans ce contexte, car le pipe n’y a pas de sens
  • Les arguments de ExecStart= n’héritent pas, par défaut, des variables d’environnement au-delà de quelques valeurs du gestionnaire système
    • le $PATH par défaut est presque vide
    • exécuter /usr/bin/env constitue une protection simple qui permet d’utiliser des éléments comme systemctl
    • ExecStart=/usr/bin/bash seul fournirait des entrées par défaut dans le $PATH, mais l’usage de env ajoute une sécurité supplémentaire
  • Il est possible d’exécuter directement le service sans timer
systemctl start roulette
  • Un service sans section [Install] ne peut pas être enable ; dans cette structure, le timer est la manière standard de lancer le service de façon cohérente
  • systemctl agit par défaut sur roulette.service même sans suffixe explicite
  • Appliquer systemctl start à une unité .timer active le timer, mais n’exécute pas immédiatement le service ciblé par Unit=
systemctl start roulette.timer
  • status indique quand le timer s’exécutera ensuite
systemctl status roulette.timer
Trigger: Sat 2026-04-18 10:00:00 MDT; 35min left
  • Le flux le plus simple consiste à créer le service cible, placer à côté un timer avec son planning, puis démarrer le timer plutôt que la cible
  • Si la section [Install] du timer contient WantedBy=, le timer peut aussi être lancé au démarrage
systemctl enable roulette.timer

Représentation du temps : événements de calendrier et durées

  • Dans les timers, la manière de représenter le planning est importante, et il faut distinguer les intervalles récurrents des événements de calendrier ou des horodatages
  • La page de manuel systemd.time(7) contient suffisamment d’exemples et constitue une première référence utile pour écrire des timers
  • systemd-analyze peut valider et expliquer les expressions temporelles
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
  • Les timers systemd peuvent définir non seulement des heures récurrentes basées sur l’horloge murale, mais aussi, contrairement au cron traditionnel, des durées récurrentes calculées à partir d’un événement antérieur
  • La forme complète de daily signifie une exécution chaque année, chaque mois et chaque jour à 00:00:00
*-*-* 00:00:00
│ │ │ │  │  ╰── at second 00
│ │ │ │  ╰───── at minute 00
│ │ │ ╰──────── at hour 00
│ │ ╰────────── every day
│ ╰──────────── every month
╰────────────── every year
  • On peut utiliser des raccourcis comme daily, la forme complète, ainsi que d’autres valeurs prises en charge par systemd.time(7), puis vérifier ses hypothèses avec systemd-analyze

Quand une exécution déclenchée par événement est plus adaptée

  • Dans les tâches réelles, il est souvent plus pertinent d’exprimer « exécuter après un autre événement » que « exécuter tous les jours à la même heure »
  • Pour le nettoyage d’un répertoire temporaire, si l’expression cron prévue vient juste de passer après le démarrage, il se peut qu’il n’y ait presque rien à supprimer dans /tmp
  • Exprimer la logique comme « exécuter une heure après le démarrage de l’ordinateur, puis toutes les heures » correspond mieux au comportement réel du service et à sa logique de planification
[Timer]
OnBootSec=1h
OnUnitActiveSec=1h
  • OnBootSec=1h signifie une exécution unique une heure après le démarrage de la machine
  • OnUnitActiveSec=1h signifie une nouvelle exécution une heure après que Unit= a été exécutée, ce qui fait implicitement tourner le timer en boucle
  • Ce type d’expression périodique basée sur une durée convient plus souvent à des usages du type « exécuter de temps en temps » qu’à des formulations comme « exécuter à telle minute de chaque heure »
  • Dans l’exemple d’un bot Slack qui interroge l’API d’Advent of Code, une expression cron */15 respecte bien la politique « toutes les 15 minutes » de l’API, mais si tout le monde interroge au même rythme, cela peut concentrer le trafic
  • Démarrer le timer après avoir modifié le code, puis le laisser s’exécuter toutes les 15 minutes, peut répondre au besoin tout en réduisant potentiellement le problème de thundering herd

Voir l’état des timers en un coup d’œil

  • systemctl list-timers est une commande de haut niveau qui résume l’état des timers sur une machine
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.
  • Une seule commande permet d’obtenir une vue d’ensemble de tout ce qui s’exécute selon des plannings de timers
  • list-timers fait partie de la famille des sous-commandes systemd souvent utiles
    • list-units est également pratique
    • list-paths est une sous-commande ajoutée plus récemment à systemctl

Réveiller le système depuis la veille pour exécuter une tâche

  • WakeSystem= permet à un timer arrivé à échéance de réveiller le système depuis la veille
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.
...
  • Cette fonction est utile lorsqu’un script important doit s’exécuter sans qu’une personne ait à ouvrir physiquement le capot d’un ordinateur portable
  • Sur des distributions comme Arch ou NixOS, qui permettent de télécharger les mises à jour avant leur installation, on peut récupérer les paquets tard dans la nuit, puis faire la mise à jour le matin devant le clavier
  • Le manuel précise que si l’on veut remettre la machine en veille après la fin du .service, il faut la remettre en veille manuellement

Répartir les heures d’exécution et atténuer le thundering herd

  • Le problème de thundering herd est un problème système qui survient lorsque plusieurs processus se réveillent en même temps
  • Si tous les systèmes Debian du monde étaient codés en dur pour lancer apt update à 00:00:00, minuit deviendrait un très mauvais moment pour les pics de trafic
  • FixedRandomDelay= et RandomizedOffsetSec= aident à répartir les heures d’exécution
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. ...
  • Ces paramètres peuvent être utilisés sur de vrais systèmes qui vérifient la disponibilité de mises à jour logicielles
  • Répartir les exécutions selon une distribution uniforme aide à réduire le problème de thundering herd, à rendre le comportement plus cohérent, et à éviter des perturbations comme des redémarrages de démons pendant la coordination de services distribués
  • Les options de timing sont globalement très configurables et offrent un contrôle fin

Rattraper immédiatement les exécutions manquées

  • Persistent= est particulièrement adapté aux scripts planifiés qui ne doivent pas être ignorés parce qu’un ordinateur portable était en veille, sans pour autant nécessiter WakeSystem=
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. ...
  • Si un système censé faire un check-in de gestion de configuration a subi une indisponibilité, il peut revenir à l’état attendu juste après sa reconnexion en activant simplement Persistent= dans le .timer
  • Sans Persistent=, il faut parfois attendre la prochaine heure normale d’exécution du timer, ce qui peut être long
  • Parmi les autres tâches pour lesquelles il ne faut pas attendre lorsqu’une activation manquée est détectée, on trouve les mises à jour système ou les vérifications de traitements batch

Points d’attention lors de l’écriture de timers

  • Les timers utilisés dans le contexte du gestionnaire utilisateur, via systemctl --user, sont également valables, mais il faut faire attention à la cible mentionnée dans [Install]
  • Selon la distribution, la cible appropriée pour des timers utilisateur peut être default.target
  • Comme avec cron, la recommandation générale de maintenir une horloge système précise reste valable
  • Les utilisateurs de systemd peuvent vérifier l’état de la synchronisation avec timedatectl timesync-status
  • De nombreux éditeurs prennent en charge nativement le format des fichiers d’unité systemd, ce qui aide lorsque ces fichiers grossissent
  • Dans Emacs, on peut utiliser le paquet emacs systemd

2 commentaires

 
GN⁺ 2026-06-02
Commentaires sur Hacker News
  • Je n’ai pas assez utilisé les timers systemd pour vraiment contredire, mais je ne vois pas bien en quoi le $PATH de cron serait ambigu
    On peut définir PATH directement dans le crontab ; je ne vois pas pourquoi ce serait moins prévisible que lorsqu’il est défini dans des endroits comme /etc/bashrc, ~/.bashrc, ~/.profile, ~/.bash_profile, /etc/systemd/…
    J’utilise Linux depuis 1994, mais je ne mémorise pas la syntaxe de cron. Cela dit, le commentaire m h dom mon dow command est déjà écrit dans le crontab, donc il suffit de mettre les chiffres en face des bons intitulés
    Je comprends le reste des critiques, et la prochaine fois que j’aurai besoin d’une tâche cron, j’essaierai probablement un timer systemd

    • « Il suffit de mettre les chiffres en face des bons intitulés » ne résume pas équitablement la critique d’origine, parce que ce n’est pas toute la syntaxe
      Il y a des virgules, des slashs, des astérisques, des combinaisons, et si on a besoin de randomisation, cron ne le gère généralement pas en natif, donc il faut l’ajouter dans la commande. Écrire une spécification cron un peu non triviale n’est pas simple
    • Pour avoir travaillé avec des applications qui prennent en charge les expressions cron, les chiffres n’en sont que la partie la plus élémentaire
      Quand quelqu’un saisit quelque chose comme 5,3/4 4-8,11 1 4,5,6,9-11 */2, on se retrouve à devoir faire de la rétro-ingénierie pour comprendre ce qu’il a réellement voulu dire, et en général ce n’est pas ce que l’expression signifie vraiment
      Et quand on y ajoute des extensions prises en charge seulement dans certains environnements cron, ça devient encore plus compliqué
      Les timers systemd étaient bien plus faciles à administrer. Le fait de pouvoir contrôler si une exécution en doublon est autorisée pour une tâche longue, ou de pouvoir exécuter une tâche dans une fenêtre entre un début et une fin plutôt qu’à une heure fixe, est une grosse amélioration
      J’ai déjà eu un backup qui est parti dans une boucle de liens symboliques et a fait tomber un VPS ; cron continuait à lancer de nouveaux backups alors que le précédent n’était toujours pas terminé
      Le PATH spécial de CRON, qui m’a obligé à réécrire des commandes et des scripts, était aussi pénible, même si certains timers systemd peuvent avoir un comportement similaire. Malgré tout, on peut lancer le timer manuellement sans devoir modifier le crontab pour le faire partir dans 30 secondes puis attendre
    • Je n’ai pas envie de coder en dur $PATH dans un crontab juste pour tester une tâche cron
      Si je ne le code pas en dur, le $PATH utilisé par cron au moment de l’exécution sera différent du $PATH quand je teste directement la commande. systemctl start foo.service lance la commande dans le même environnement que lorsque le timer se déclenche, donc je peux savoir si elle fonctionnera de la même manière
      À l’inverse, une tâche cron s’exécute à l’heure définie dans le crontab. Les timers systemd se déclenchent eux aussi le plus souvent à l’heure prévue, mais à cause de bugs logiques dans systemd, il peut arriver qu’un timer exécuté une fois le 29 février ne se relance plus jamais, ou qu’il se déclenche — ou non — quand on « redémarre » l’unité timer
    • L’avantage de l’environnement systemd, c’est qu’il est standardisé et presque vide. À l’inverse, l’environnement d’un crontab est complètement différent de celui hérité par supervisord ou les scripts sysvinit, et je me suis souvent fait piéger par ça
      Avec systemd, quelle que soit la source du déclenchement, c’est la même unité qui est réellement exécutée, donc il n’y a pas ce décalage
      Il faut toujours savoir quel est l’environnement par défaut, mais il est presque propre et n’est pas affecté par le shell. À mes yeux, c’est un point fort de systemd
    • Je n’irais pas jusqu’à dire que PATH est ambigu, mais cron a bien des problèmes liés à PATH
      Il manque dans les valeurs par défaut des chemins qu’on s’attendrait à y trouver, comme /usr/local/bin ou /usr/sbin pour root, et certaines distributions comme Arch Linux n’indiquent même pas dans leurs pages de manuel le chemin par défaut ni de recommandation de configuration
      Si on veut ajouter un chemin à un seul script précis, il faut l’envelopper avec env, le définir dans un script wrapper, ou modifier le chemin avant l’entrée puis le rétablir ensuite
      On ne peut pas utiliser ~ ni $HOME dans PATH, il faut écrire le chemin absolu complet, ce qui est particulièrement pénible dans les crontabs utilisateur
      Ce ne sont pas des contournements difficiles, mais par défaut, le fait que les timers systemd utilisent le même chemin que les autres services me paraît offrir une meilleure expérience
  • Je suis passé de cronie aux timers systemd parce qu’ils sont plus souples vis-à-vis de l’heure de démarrage du système
    Ma stratégie de sauvegarde consiste à créer chaque jour une entrée d’archive borg à heure fixe, mais avec cronie, le système doit être allumé au moment prévu. Les timers systemd supportent ce cas et exécutent le service dès que le système redevient disponible
    Le dépôt d’automatisation des sauvegardes est https://github.com/gchamon/borg-automated-backups

    • Cronie dispose pour cela d’un mécanisme appelé anacron. Sur mon système, cron appelle /etc/cron.hourly/0anacron toutes les heures et exécute les tâches de /etc/cron.{daily,weekly,monthly} même si leur heure d’exécution la plus tôt a été manquée. On peut aussi configurer un délai aléatoire
      En modifiant /etc/anacrontab, on peut créer des planifications personnalisées
      Au niveau utilisateur, on pourrait probablement mettre quelque chose comme @hourly anacron -t /path/to/anacrontab -S /path/to/spooldir dans son crontab utilisateur, mais je ne l’ai jamais fait moi-même
      Beaucoup d’implémentations de cron ont un mécanisme similaire
    • cron a l’option @reboot, et je l’utilise dans quelques scripts ; ça fonctionne bien
    • Cronie n’a pas de méta-déclencheur @reboot ?
  • Je ne fais pas confiance aux buses des imprimantes Canon, qui peuvent se boucher si elles restent inutilisées un moment. Du coup, j’ai demandé à Claude de créer un script systemd qui imprime chaque semaine des photos de chiens, avec suffisamment de spectre CMYK pour faire travailler l’imprimante
    Le lundi, quand je m’assois à mon bureau, c’est une surprise assez sympa de voir une photo sortir soudainement de l’imprimante

    • Ce serait bien qu’au lieu de gaspiller de l’encre dans une éponge tous les quelques jours, l’imprimante ait un mode qui imprime des images aléatoires depuis un album ou un calendrier
      Au moins, ça pourrait faire une idée de projet pour un concours scientifique d’enfants
    • Mon père avait un modèle proche de la Deskjet 720
      Après sa mort, elle est restée éteinte et inutilisée pendant des années, puis j’ai eu besoin d’une impression couleur : je l’ai simplement rebranchée et lancée
      Au bout d’environ 1/5 de la première page, toutes les couleurs étaient revenues, et elle a ensuite imprimé une vingtaine de pages sans problème
    • J’ai fait quelque chose de similaire avec une vieille Samsung ML-2010 quand j’étais en début d’université
      Ça semblait plus être un problème logiciel que matériel : si l’imprimante restait connectée à l’ordinateur sans être utilisée pendant plus d’une semaine, elle arrêtait simplement d’imprimer
      J’aurais pu fouiller les logs, mais à la place j’ai créé une tâche cron qui imprimait une page de test tous les lundis et jeudis. En haut de la page, il y avait juste une phrase du genre LOL PRINTER WORKS
      En fait, ce n’était pas si gaspillé que ça. Je suivais beaucoup de cours de maths, donc j’avais énormément besoin de papier brouillon imprimé au verso pour résoudre des exercices ; j’utilisais d’abord les impressions ratées ou de test avant de prendre des feuilles vierges
    • La solution, c’est une imprimante laser. Rien qu’avec les économies sur les consommables, elle finit par être rentabilisée
    • J’allais recommander une imprimante couleur LED OKI bon marché, mais ils se sont retirés du marché grand public
      La résolution maximale n’était que de 600 dpi, mais les couleurs étaient très belles et uniformes, et le fait que le toner ne sèche pas était le critère d’achat principal de mon frère. Les jets d’encre HP se sont bouchés plusieurs fois
  • J’adore les timers systemd. J’ai progressivement migré toutes les tâches cron que je déployais avec Ansible vers des timers, et maintenant il suffit qu’Ansible les copie
    L’intégration avec journalctl est particulièrement appréciable, et elle l’est encore plus sur les OS récents où syslog a disparu, comme Debian 13. Le fait de pouvoir démarrer manuellement le service pour déboguer est aussi pratique
    Avec une tâche cron qui ne marche pas, il faut se coltiner du copier-coller ou des scripts shell supplémentaires, sans parler du trou noir dans lequel disparaît la sortie standard des tâches cron
    On peut surveiller le service systemd comme d’habitude et recevoir des alertes en cas d’échec. J’apprécie aussi que les projets open source recommandent de plus en plus les timers comme méthode de déploiement

    • Ça me va qu’un projet recommande les timers, mais pour être satisfait il faut que je puisse l’ignorer et utiliser cron
  • NixOS utilise systemd par défaut et en fait un élément de première classe pour l’administration. C’est particulièrement agréable quand on vient de launchd sur macOS
    J’aime aussi le fait que, lorsqu’on distribue des outils pour NixOS, on puisse exploiter systemd de manière naturelle au lieu de l’ajouter comme un bricolage par-dessus
    En revanche, si on distribue un outil avec beaucoup de gestion de cycle de vie à l’ensemble des utilisateurs Linux, je me demande quoi faire, puisque systemd n’est pas présent partout
    Je fais tourner le scrub mensuel d’un pool btrfs avec un timer systemd. C’est assez utile, parce qu’on peut décider d’ignorer l’exécution suivante si l’utilisateur lance lui-même un scrub, ou bien choisir, pour une tâche mensuelle, s’il faut accumuler les exécutions manquées quand la machine est restée éteinte 6 mois, ou les regrouper en une seule

    • Sur NixOS, les tâches systemd sont vraiment faciles. Il vaut mieux définir les unités en Nix que se battre avec des fichiers INI
      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" ]; };
    • Je me demande si tu les définis directement dans le fichier flake.nix
      J’utilise aussi NixOS, mais je garde toute ma configuration dans le format d’origine et je ne fais qu’ajouter des liens symboliques avec Nix. Comme ça, je peux facilement réutiliser la config sur des systèmes non-NixOS aussi
      Le problème, c’est que NixOS n’a pas l’air de prendre en charge et lancer les timers et services systemd placés dans le dossier ~/.config/systems/user, et même quelque chose comme WantedBy=default.target ne semble avoir aucun effet
      Donc, après avoir redémarré manuellement tous les services après un reboot, je finis par reconnaître que les timers systemd sont géniaux
  • Les timers peuvent fonctionner non seulement avec un service du même nom, mais aussi avec n’importe quelle unité, ce qui les rend étonnamment flexibles
    Sur mon serveur, j’ai un timer qui lance backup.target, lequel exécute chaque matin tout le cycle de sauvegarde restic backup, restic prune, restic forget, avec une heure de démarrage aléatoire et des notifications
    Les unités restic-* elles-mêmes sont des Podman Quadlet, donc tant qu’il y a Podman et Systemd sur le serveur, la configuration fonctionne indépendamment du contenu du serveur
    Cela dit, les timers sont l’un des types d’unités systemd les plus grossiers pour un usage quotidien. Je comprends pourquoi c’est séparé en deux fichiers et pourquoi la syntaxe de start et enable est différente, mais parfois j’aimerais juste créer un seul fichier, exécuter un script, et en finir

    • J’utilise une configuration similaire pour les sauvegardes. Il m’est déjà arrivé de désactiver le timer pour faire ponctuellement d’autres opérations sur le dépôt restic, comme nettoyer des verrous, puis de me faire surprendre parce qu’une unité déjà déclenchée tournait encore
    • On dirait qu’il faudrait une couche d’abstraction supplémentaire au-dessus des unités systemd. Ce serait bien qu’un outil déclaratif en ligne de commande s’en charge au lieu d’éditer directement les fichiers
      À l’époque des LLM, ce n’est peut-être plus vraiment un problème, mais ça reste légèrement pénible à chaque fois
    • Je me demande pourquoi tu randomises l’heure des sauvegardes
  • Je n’ai pas toujours été un grand fan de tous les aspects de systemd, mais je suis globalement d’accord avec ce point de vue.
    Pour les tâches planifiées au niveau du « système », j’ai presque complètement arrêté d’utiliser cron et je préfère désormais les timers systemd. Pour la planification limitée à une application précise, on peut aussi intégrer quelque chose comme Quartz.
    La raison est un peu floue et difficile à expliquer, mais l’approche systemd correspond plus proprement au modèle mental que j’ai de « la bonne façon dont ça devrait marcher ». J’ai aussi souvent eu par le passé des exécutions de scripts cron rendues imprévisibles à cause d’un PATH ambigu, sans que ce soit la seule raison.
    Je ne prétends pas que les timers systemd sont universellement et objectivement meilleurs que cron, mais ils ont au moins réussi à me convaincre.

  • C’était une excellente introduction aux timers systemd, et c’était assez convaincant pour enfin me donner envie de les essayer.
    J’aime aussi list-timers. Avec cron, il n’était pas simple d’avoir une vue d’ensemble de tous les jobs cron exécutés sur une machine. Il fallait vérifier les crontabs de tous les utilisateurs, /etc/cron.d/, ainsi que les répertoires daily/hourly/monthly.
    J’ai justement un cas d’usage où quelque chose doit s’exécuter une fois environ 5 minutes après le démarrage, puis environ toutes les 12 heures, donc c’est bien de voir que les timers systemd gèrent ça.

    • Merci pour le compliment. Vu à quel point systemd est utilisé aujourd’hui, j’ai vraiment le sentiment qu’il vaut la peine d’apprendre à utiliser des outils comme systemd-analyze et systemctl list-timers.
  • systemd semble complexe au premier abord, mais une fois qu’on l’utilise, on n’a plus envie d’utiliser autre chose. C’est pratique de tout gérer avec systemctl.

    • Il reste dans sa conception des choix étranges que je ne comprends toujours pas complètement.
      Par exemple, je ne vois pas pourquoi les définitions d’unités doivent nécessairement être de vrais fichiers sur disque. Quand le démon relit sa configuration, il relit tous les fichiers, pas seulement ceux qui ont changé. Je me demande pourquoi il n’existe pas une API pour ajouter des unités de manière programmatique. Il existe bien des choses approchantes, mais avec beaucoup de contraintes et peu de souplesse.
      Le fait de ne pas pouvoir déclarer plusieurs unités dans un seul fichier me laisse aussi perplexe. La conception est centrée sur le système de fichiers, et le choix de ne pas proposer un autre niveau d’abstraction ne me paraît pas très intelligent. Ce n’est pas spécialement fidèle non plus à la philosophie Unix.
      Pour le format des définitions d’unités aussi, je me dis que si TOML avait existé à l’époque, ils auraient pu choisir quelque chose de plus raisonnable.
    • systemd a en fait des pages de manuel vraiment utiles.
    • D’autres le voient autrement. Après l’avoir essayé, c’est justement quelque chose qu’ils n’ont plus envie d’utiliser. Je déteste systemd, sincèrement.
      Mais bon, c’est sûrement parce que je suis vieux. Évidemment, systemd-* serait l’unique voie correcte, et tous ceux qui pensent autrement ne seraient que des donneurs de leçons.
    • Je déteste toujours la journalisation de journald.
    • C’est un point de vue assez moderne. Quand systemd est apparu, les gens le détestaient vraiment, mais moi je l’ai toujours aimé et je pensais que les gens finiraient par l’accepter. Ça fait plaisir de voir que c’est effectivement arrivé.
  • J’utilise Linux depuis plus de 20 ans, et systemd depuis plus de 10 ans.
    Et pourtant, il y a toujours quelque chose de nouveau à apprendre, et je finis encore par le considérer comme un autre outil utile.

    • J’utilise Linux depuis une trentaine d’années et, apparemment, nous avons donc tous eu tort d’utiliser cron pendant des décennies.
 
GN⁺ 2026-06-02
Avis sur Lobste.rs
  • systemd n’est pas parfait, mais j’ai l’impression que beaucoup de ses choix de conception s’appuient sur des leçons tirées des approches plus traditionnelles d’autrefois
    J’ai récemment réécouté l’épisode de 2015 de CRE où Lennart Poettering en explique le contexte, et ça reste recommandable aujourd’hui

  • Je fais plutôt partie de ceux qui n’aiment pas systemd jusqu’au bout des ongles, mais je considère systemd.timers comme l’un des concepts “les moins mauvais” de ce produit
    C’est pourquoi j’ai été un peu surpris de voir l’auteur le défendre en rabaissant les gens qui ont des critiques légitimes
    Cela dit, j’aime bien l’utiliser avec la commande at. Pour une commande à exécuter une seule fois à une heure précise, j’utilise at, et pour le reste, des timers systemd avec des fichiers d’unité simples
    L’amélioration que j’aimerais le plus voir, c’est de pouvoir savoir quel utilisateur exécute un timer. Je suis certes l’un des rares à encore administrer une shell box en 2026, mais il serait utile de savoir quel utilisateur a créé un timer qui martèle le disque à chaque seconde

    • Pour cet usage, ne pourrait-on pas utiliser des unités utilisateur au lieu de faire installer des timers système à tout le monde ?
      Si je comprends bien, avec loginctl enable-linger, cela peut fonctionner même sans session utilisateur active. Bien sûr, il y a sans doute des cas d’usage où ce n’est pas suffisant, et je ne connais pas le contexte précis
  • J’aimerais surtout que les timers systemd aient une barrière à l’entrée plus faible, en particulier du côté de la gestion utilisateur
    Vu la quantité de configuration nécessaire, il est vraiment difficile de battre crontab -e

    • L’approche systemd, qui exige plusieurs fichiers de configuration et services pour définir un seul timer… en termes de choix d’API, c’est difficilement défendable
  • Après m’être longtemps demandé comment centraliser proprement les logs des scripts cron, j’ai fini par comprendre qu’il suffisait d’utiliser des timers systemd
    Le problème de journalisation est résolu. Je n’ai plus aucune raison de revenir à cron, et j’aurais aimé le savoir plus tôt

    • On ne peut pas simplement faire un pipe vers logger, ajouter à un fichier de log avec >>, ou laisser le comportement par défaut et recevoir un e-mail ?
  • Vous pouvez trouver ça vieillot, mais je garde encore les e-mails du serveur configurés pour m’atteindre
    Une fois automatisé, ça vient gratuitement avec chaque nouvel hôte, et c’est assez pratique au quotidien
    Par exemple, j’ouvre un multiplexeur, je lance long_running_process | mail root@localhost -s "done $?", puis je l’oublie

  • Bon article, et j’avais moi aussi un brouillon sur un sujet similaire, que j’ai dû reconsulter récemment
    Si, comme moi, vous vous engagez dans le terrier systemd, je recommande de placer les fichiers d’unité et les timers dans le dossier du projet concerné, puis de les lier symboliquement vers /etc/systemd/system/
    Un de mes reproches envers systemd est qu’il ne distingue pas les unités installées par la distribution de celles écrites à la main, mais avec des liens symboliques on peut maintenir soi-même cette séparation

    • En réalité, cette distinction est gérée par le chemin
      Les unités système/paquet/distribution vont dans /usr/lib/systemd/system, tandis que les overrides locaux ou les unités locales vont dans /etc/systemd/system