Timer systemd qui ne se déclenche pas : le diagnostic en cinq vérifications

Un timer systemd qui ne se déclenche pas reste le plus souvent à l’état waiting, et la cause se trouve dans une autre unité que celle qu’on inspecte. Quatre chemins mènent à ce silence : un timer jamais démarré, un service absent, une section [Install] vide, un fichier modifié que le gestionnaire n’a pas relu. Les pages de manuel livrées avec Debian 12 portent le numéro 252.36-1~deb12u1, et ce sont elles qui servent de référence. La rubrique automatiser des tâches sous Linux regroupe les procédures voisines.
Sommaire
- Vérification 1 : active (waiting) signale un timer armé
- Vérification 2 : le service visé porte le nom du timer
- Vérification 3 : un timer qui démarre au boot répond enabled
- Vérification 4 : la prochaine échéance se calcule à l’avance
- Vérification 5 : le journal sépare le timer et le service
- Un service RemainAfterExit=yes n’est activé qu’une fois
- Deux fichiers suffisent à expliquer un timer silencieux
- Sources
Le cas typique est une sauvegarde hebdomadaire : un fichier /etc/systemd/system/sauvegarde.timer doit déclencher sauvegarde.service. Le gestionnaire ne devine rien, et la page systemd.timer(5) fixe la règle de nommage, un fichier foo.timer active foo.service, sauf mention contraire de la directive Unit=.
Vérification 1 : active (waiting) signale un timer armé
L’état du timer se lit sur une seule ligne, et la mention active (waiting) veut dire que l’échéance est programmée. Ce mot waiting vient de la table d’états du logiciel : le dépôt systemd définit cinq sous-états pour un timer, dead, waiting, running, elapsed et failed, dans le fichier src/basic/unit-def.c. Un timer en dead est arrêté, un timer en failed a échoué au démarrage, et waiting correspond à la position normale entre deux passages.
La commande qui affiche cette ligne est systemctl status. Le tableau de systemctl list-timers la complète avec NEXT, la prochaine date, et LEFT, le temps restant ; le wiki Arch rappelle que l’option –all y ajoute les timers inactifs, absents de l’affichage par défaut. Les colonnes LAST et PASSED restent à n/a tant que le service n’a pas été lancé une première fois.
systemctl status sauvegarde.timer
systemctl list-timers --all 'sauvegarde.timer'
Un timer qui refuse de s’armer laisse deux messages dans son journal, et le wiki Arch les relève pour l’option WakeSystem=.
Failed to enter waiting state: Operation not supported
Failed with result 'resources'.
Ces deux lignes signalent une option que la machine ne peut pas honorer. La page systemd.timer(5) précise que WakeSystem= demande des privilèges et reste réservé au gestionnaire système, avec false comme valeur par défaut. Le remède tient en un geste : retirer la ligne WakeSystem=true du fichier, recharger avec systemctl daemon-reload, puis redémarrer le timer.
À l’écran : Active: active (waiting) pour sauvegarde.timer, et une date dans la colonne NEXT.
Vérification 2 : le service visé porte le nom du timer
Le fichier du service existe-t-il sous le nom attendu ? La page systemd.timer(5) répond par une règle de nommage, et un renommage partiel casse le lien sans bruit. Un timer acquiert en plus une dépendance Before= sur le service qu’il doit activer, notée dans la même page.
Trois commandes suffisent à lever le doute. La première affiche le contenu réel du fichier, section [Timer] comprise. La deuxième montre si l’unité visée existe. La troisième, systemd-analyze verify, est décrite dans la page systemd-analyze(1) livrée avec Debian 12 : elle charge le fichier et signale les directives inconnues comme les dépendances absentes.
systemctl cat sauvegarde.timer
systemctl status sauvegarde.service
systemd-analyze verify /etc/systemd/system/sauvegarde.timer
Quand le service n’existe pas, la réponse ne laisse aucune place au doute.
Unit sauvegarde.service could not be found.
Ce message vient d’un nom mal orthographié, d’un suffixe oublié ou d’un fichier jamais créé. Le remède est de créer l’unité manquante, ou de pointer le timer vers la bonne avec la directive Unit=, puis de recharger le gestionnaire.
À l’écran : la section [Timer] du fichier et le nom de l’unité, sans aucun avertissement de systemd-analyze verify pour un fichier correct.
Vérification 3 : un timer qui démarre au boot répond enabled
L’activation au démarrage se lit avec une seule commande, et la réponse attendue est enabled. La page systemctl(1) énumère les autres réponses possibles, dont trois expliquent un timer muet : disabled, static et indirect. Un timer static ne part jamais au démarrage, faute d’instructions d’installation, et un timer disabled attend un lancement manuel.
La section [Install] du fichier porte la ligne qui décide, et le wiki Arch donne la valeur à y écrire : WantedBy=timers.target. La page systemctl(1) précise que la commande enable crée les liens réclamés par cette section sans démarrer l’unité, ce qui justifie l’option –now quand on veut les deux d’un coup.
systemctl is-enabled sauvegarde.timer
sudo systemctl enable --now sauvegarde.timer
Un fichier modifié après sa première lecture n’est pas relu de lui-même, et le gestionnaire le dit au passage.
Warning: The unit file, source configuration file or drop-ins of sauvegarde.timer changed on disk. Run 'systemctl daemon-reload' to reload units.
La cause est une édition du fichier intervenue après son chargement en mémoire, et le remède est la commande que le message nomme, sudo systemctl daemon-reload, à exécuter avant toute conclusion.
À l’écran : enabled sur la première ligne, puis aucun avertissement après le rechargement.
Vérification 4 : la prochaine échéance se calcule à l’avance
La date suivante se vérifie sans attendre, avec le verbe calendar de systemd-analyze. La page systemd-analyze(1) livrée avec Debian 12 décrit cette commande : elle reprend la syntaxe du OnCalendar= et affiche quand l’expression repasse. La sortie porte quatre libellés, Original form, Normalized form, Next elapse et From now, et l’option –iterations en enchaîne plusieurs d’affilée.
Deux formes courtes expliquent bien des surprises de planification, documentées dans la page systemd.time(7) : weekly vaut Mon *-*-* 00:00:00, et daily vaut *-*-* 00:00:00. Un timer écrit avec weekly ne part donc pas une semaine plus tard à l’heure du fichier, mais le lundi à minuit.
systemd-analyze calendar --iterations=3 'Mon..Fri 22:30'
systemd-analyze calendar weekly
Un timer qui part en retard ou qui saute un passage ne doit pas toujours à une erreur de calcul. La page systemd.timer(5) fixe les valeurs par défaut qui expliquent la plupart des écarts.
| Directive | Valeur par défaut | Effet sur le déclenchement |
|---|---|---|
| AccuracySec= | 1min | l’échéance tombe dans une fenêtre d’une minute après l’heure écrite |
| RandomizedDelaySec= | 0 | aucun retard aléatoire ajouté au tir |
| Persistent= | false | aucun rattrapage après une extinction, même avec OnCalendar= |
| RemainAfterElapse= | true | un second démarrage du timer n’a plus d’effet |
| FixedRandomDelay= | false | le décalage change à chaque échéance |
| WakeSystem= | false | aucun réveil de la machine suspendue |
Deux réglages du tableau se corrigent dans le fichier. Persistent=true rattrape l’échéance manquée pendant une extinction, et le wiki Arch situe l’horodatage dans /var/lib/systemd/timers. AccuracySec=1us resserre la fenêtre au maximum, mais la page systemd.timer(5) rappelle que le gestionnaire place volontairement les tirs à une position stable pour limiter les réveils du processeur.
Une limite de version mérite d’être connue : un timer écrit avec OnCalendar= est automatiquement ordonné après time-sync.target, et la page systemd.timer(5) conseille d’activer systemd-time-wait-sync.service sur une machine sans horloge à pile, sans quoi l’échéance peut partir à une heure fausse.
À l’écran : la ligne Next elapse avec une date précise, et un délai dans From now.
Vérification 5 : le journal sépare le timer et le service
Le journal conserve l’histoire de chaque unité séparément, et l’option -u limite la lecture à un nom. Un timer qui a tiré laisse donc des lignes datées portant le nom du service, même si celui-ci est retombé en inactive (dead) depuis longtemps, situation normale pour un Type=oneshot que le wiki Arch signale comme telle.
La lecture se fait sur les deux unités, et le vocabulaire du journal reste constant : la réussite s’écrit Deactivated successfully, l’échec se reconnaît au résultat.
journalctl -u sauvegarde.service --since "3 days ago"
journalctl -u sauvegarde.timer --since "3 days ago"
sauvegarde.service: Deactivated successfully.
sauvegarde.service: Failed with result 'exit-code'.
La première ligne signe une exécution propre, la seconde un script sorti en erreur, que systemctl –failed regroupe aussi. Le remède se trouve dans la sortie du script, quelques lignes au-dessus dans le même journal.
Un timer sans aucune ligne datée n’a jamais tiré, même si son état reste active (waiting). Un timer systemd qui ne se déclenche pas laisse en revanche toujours une trace de son armement, et la reprise après un échec détaille la suite à donner à un service qui sort en erreur.
À l’écran : au moins une ligne datée portant sauvegarde.service, avec le résultat de la dernière exécution.
Un service RemainAfterExit=yes n’est activé qu’une fois
Le piège coûteux se cache dans le fichier du service, et la page systemd.timer(5) le décrit sans détour : un service déjà actif au moment de l’échéance n’est pas relancé, il est laissé en l’état. La même page ajoute que les services dotés de RemainAfterExit= se prêtent mal à un timer répétitif, puisqu’ils sont activés une fois avant de rester présents.
La conséquence est un timer qui tire à chaque échéance sans que rien ne se passe : le service s’affiche en active (exited) en permanence, et le nom exited figure bien dans la table d’états publiée dans le dépôt systemd. Le contrôle tient en deux commandes.
systemctl status sauvegarde.service
systemctl cat sauvegarde.service
À l’écran : active (exited) sur la ligne Active, et RemainAfterExit=yes dans le fichier. Le remède est de retirer cette ligne, puis de recharger avec systemctl daemon-reload et de repartir.
Une asymétrie du même genre existe entre directives monotones. La page systemd.timer(5) indique qu’un OnBootSec= ou un OnStartupSec= déjà dépassé déclenche le service immédiatement à l’armement, ce qui n’est pas le cas des autres directives comme OnUnitActiveSec=. Dans un conteneur, la même page ramène OnBootSec= à OnStartupSec= pour le gestionnaire système, et le calcul change.
Deux fichiers suffisent à expliquer un timer silencieux
Un timer systemd ne lance rien lui-même : il demande au gestionnaire de démarrer une unité, et le sort d’une échéance dépend du couple formé par le fichier du timer et celui du service. Un défaut dans l’un des deux produit exactement le même symptôme, un timer active (waiting) suivi d’un service qui ne bouge pas. Le nom à activer, écrit dans le fichier du timer, reste le point de départ de toute vérification.
Faut-il activer le fichier .timer ou le fichier .service ?
Le timer, et lui seul. systemctl enable –now sauvegarde.timer crée le lien réclamé par la section [Install] et démarre l’unité dans la foulée ; la page systemctl(1) rappelle que enable ne démarre rien par lui-même, d’où le –now. Le wiki Arch note que le fichier .service n’a pas besoin de section [Install], puisque c’est le timer qui est activé. Pour une première tâche planifiée, la mise en place pas à pas est décrite dans automatiser une petite routine.
Mon script tourne une fois, puis plus rien : quelle directive retirer ?
RemainAfterExit=yes, dans le service. La page systemd.timer(5) explique qu’un service déjà actif n’est pas relancé à l’échéance suivante, et qu’un service marqué RemainAfterExit= reste actif une fois lancé. Retirez la ligne du fichier, rechargez avec systemctl daemon-reload, puis vérifiez que la ligne Active du service repasse par inactive (dead) entre deux créneaux.
Pourquoi un timer utilisateur s’arrête-t-il à la fermeture de ma session ?
Le gestionnaire utilisateur disparaît avec la dernière session, et ses timers avec lui. La page loginctl(1) livrée avec Debian 12 documente la commande qui le maintient au-delà des déconnexions : loginctl enable-linger $USER. Le contrôle se fait avec loginctl show-user $USER -p Linger, qui affiche Linger=yes après l’activation.
Comment connaître la prochaine date sans attendre l’échéance ?
La page systemd-analyze(1) documente le verbe calendar : systemd-analyze calendar –iterations=3 ‘Mon..Fri 22:30’ affiche Original form, Normalized form, Next elapse et From now pour les trois prochaines échéances. L’option –base-time déplace le calcul à une date choisie, ce qui sert à vérifier un passage d’heure d’été ou un changement de mois.
Persistent=true rattrape-t-il une exécution manquée hors tension ?
Oui, mais seulement pour un timer écrit avec OnCalendar=. La page systemd.timer(5) fixe false comme valeur par défaut et réserve Persistent= aux échéances calendaires. L’horodatage conservé sur disque se nettoie avec systemctl clean –what=state sauvegarde.timer : le wiki Arch propose de supprimer à la main le fichier stamp-* dans /var/lib/systemd/timers, et la page systemctl(1) donne la commande qui s’en charge sans avoir à retrouver son nom.
AccuracySec=1min décale-t-il vraiment l’échéance ?
Oui, d’au plus une minute. La page systemd.timer(5) place le tir dans une fenêtre qui commence à l’heure écrite dans OnCalendar= et se termine avec la valeur d’AccuracySec=, à une position stable choisie par la machine. Ce réglage sert à regrouper les réveils du processeur, et le wiki Arch conseille AccuracySec=1us quand la minute compte.
Sources
- systemd.timer(5), documentation du projet systemd pour les directives, les valeurs par défaut et la règle de nommage entre timer et service.
- systemd-analyze(1), page de manuel livrée avec Debian 12 (systemd 252.36-1~deb12u1) pour les verbes calendar et verify.
- Systemd/Timers, wiki Arch Linux pour list-timers –all, les fichiers d’horodatage et les timers utilisateur.
- src/basic/unit-def.c, dépôt officiel systemd pour la table des sous-états d’un timer et d’un service.