Cron ou timers systemd : cron lit des lignes, les timers exécutent des unités
Le même job de 03:30 sur les deux horloges — courrier silencieux contre journalisation, runs sautés contre Persistent=true, et la table de décision pour savoir où atterrit votre prochain job.
Machine systemd à vous → timer. Jobs d'une ligne, conteneurs, machines que vous n'avez pas installées → cron.
Cron échoue en silence — il met un courriel dans une boîte locale que personne ne lit. Les timers loguent chaque exécution dans le journal : journalctl -u mytimer.service.
Persistent=true relance les jobs manqués pendant que la machine était éteinte ; cron les saute en silence.
LES DEUX HORLOGES
Le même job — sauvegarde nocturne à 03:30 — sur les deux horloges, et ce que chacune laisse derrière elle :
CRON · une ligne
30 3 * * * /usr/local/bin/backup.sh
s'exécute quand l'horloge murale correspond. Si ça échoue, la sortie part en courriel dans une boîte locale — d'ordinaire non lue. Machine éteinte à 03:30 ? Sauté, en silence.
a-t-il vraiment tourné ? journalctl -u cron -n 20 ou grep CRON /var/log/syslog
TIMER SYSTEMD · deux fichiers d'unité
# foo.timer
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
# foo.service — the job itself
une unité de première classe : statut, dépendances, logs par exécution dans le journal. Machine endormie à l'heure dite ? Persistent=true le fait tourner une fois au boot.
vérifier ça : systemd-analyze calendar "*-*-* 03:30:00" — le prochain déclenchement, avant de sauver
le verdict des plannings : les cinq champs de cron sont l'incumbent compact ; OnCalendar est plus bavard mais strictement plus expressif — Mon..Fri 09..17:00:00 tient en une ligne, et RandomizedDelaySec empêche mille machines de marteler un seul serveur
ces horloges re-horodatent d'après les propres commandes du dossier — elles ne peuvent pas lire le journal de votre machine ; où est réellement votre journal : sections 04 et 05.
LES ÉCARTS PRATIQUES
- Logging : les timers loguent stdout/stderr dans le journal, par unité ; cron au mieux met un courriel à l'utilisateur local.
- Runs manqués : un timer avec
Persistent=truetourne une fois au boot si son planning a été manqué ; cron saute sans un mot. - Dépendances : les timers savent attendre
network-online.targetou des points de montage ; cron, il faut bricoler la logique de retry à la main dans le script. - Syntaxe : cron, une ligne ; un timer, deux fichiers. C'est tout le coût du basculement.
- Option monotonic:
OnBootSec=15min— les changements d'horloge murale ne peuvent pas le troubler.
04TESTER UN TIMER SANS ATTENDRE
Trois commandes répondent à tout — lister ce qui est planifié et quand ça déclenchera, tourner le job à la main exactement comme le timer le ferait, puis lire ses logs :
systemctl list-timers --all # every timer, next + last run
sudo systemctl start backup.service # fire the job now, same unit as the timer
journalctl -u backup.service -f # watch its output live
Notez la répartition : systemctl start backup.timer arme le planning ; le service est le job. Si list-timers montre votre timer, systemctl status backup.service est vert, et le journal montre votre sortie, toute la chaîne marche.
verify: systemctl list-timers --all → votre timer, dernière et prochaine exécutions listées
05LANCER UN JOB CRON À LA MAIN
Les jobs cron tournent avec un environnement dépouillé, voilà pourquoi « ça marche dans mon shell, ça rate dans cron » est un genre de bug à part entière. Pour reproduire cron fidèlement, lancez la commande via sh avec l'environnement que cron utiliserait :
crontab -l # confirm the exact line
env -i SHELL=/bin/sh PATH=/usr/bin:/bin sh -c '/usr/local/bin/backup.sh'
grep CRON /var/log/syslog | tail # did cron even fire it? (Debian/Ubuntu)
journalctl -u cron -n 20 # same, on systemd distros
Cette env -i ligne est le test manuel honnête : un environnement nu avec le PATH par défaut de cron. Les deux classiques de cron — un PATH nu et un % non quoté (cron le traite comme un retour à la ligne) — apparaissent immédiatement dans ce test.
verify: journalctl -u cron -n 20 → l'entrée CRON de votre commande
« MON TIMER NE SE DÉCLENCHE PAS »
Un timer qui semble mort a d'ordinaire un service qui échoue instantanément. Quatre causes, dans l'ordre où les vérifier :
- Les noms du service et du timer ne correspondent pas.
foo.timerdéclenchefoo.service— une coquille ou une unité renommée, et le timer « tourne » dans le vide.systemctl cat foo.timermontre exactement ce qu'il vise. - Édité mais pas rechargé. Après modification d'un fichier d'unité :
sudo systemctl daemon-reload && sudo systemctl restart foo.timer. Sans ça, votre nouveau planning n'est pas vivant. - Mauvaise commande de statut.
systemctl status foo.timermontre toujours active même au repos — lisezlist-timersà la place. - Le service qu'il déclenche échoue instantanément.
journalctl -u foo.service --since -1hmontre le crash quelist-timerscache.
verify: journalctl -u foo.service --since -1h → le crash que list-timers cache
LA TABLE DE DÉCISION
| cron | timer systemd | |
|---|---|---|
| Installation | une ligne de crontab | deux fichiers d'unité |
| Logging | courriel local, d'ordinaire non lu | journal, par unité |
| Run manqué (machine éteinte) | sauté | tourne une fois avec Persistent=true |
| Dépendances / ordre | aucune — à faire main dans le script | dépendances d'unité complètes |
| Délai randomisé | à faire main avec $RANDOM | RandomizedDelaySec= |
| Test / dry-run du planning | non | systemd-analyze calendar |
| Existe partout | oui — conteneurs, BSD, embarqué | exige systemd (PID 1) |
| Jobs d'utilisateur sans root | crontab -e | systemd --user unités |
Règles de pouce : livrer un job sur votre propre machine systemd → timer. Rappel perso rapide, ou une machine que vous n'avez pas installée → cron. Tout ce qui a des dépendances, des retries, ou le besoin de savoir si ça a vraiment tourné → timer, toujours. Le patron classique — une sauvegarde rsync nocturne sous un timer avec Persistent=true — garantit que la sauvegarde arrive même si la machine dormait à la minute prévue, ce que cron ne peut simplement pas offrir.
fin des deux horloges · rien n'a été téléchargé · tout est local