Convert a cron job into a timer that reports failure
Task
Take a backup job running under cron, convert it to a systemd timer, and gain the property cron does not give you: a failing run is visible without anyone having to read mail. Then prove the difference by making the job fail.
Steps
- Write a backup script that tars a directory to
/backupsand exits non-zero if the source is missing. Put it at/usr/local/bin/backup.sh. - Install it as a cron entry running every minute. Let it run, then make it fail by removing the source directory. Observe that nothing anywhere reports the failure unless you go looking.
- Remove the cron entry. Write
backup.serviceas aType=oneshotunit invoking the same script. - Write
backup.timerwithOnCalendar=*:0/1for testing, and a[Install]section wantingtimers.target. -
daemon-reload, thenenable --now backup.timer. Confirm withsystemctl list-timersthat it is scheduled and shows the next run. - Let it succeed once, then make it fail again. This time confirm that
systemctl status backup.servicereports the failure and the exit code, and thatjournalctl -u backup.serviceholds the output. - Add
Persistent=trueand explain what it does for a machine that was switched off when the timer should have fired.
Verify
systemctl list-timers --all | grep backup
systemctl is-enabled backup.timer
# after making it fail:
systemctl status backup.service --no-pager | grep -qi 'failed' && echo "failure visible"
journalctl -u backup.service -n 5 --no-pager | tail -3
systemctl show backup.service -p ExecMainStatus --value # non-zero
The contrast with step 2 is the whole lab: under cron the failure was silent unless somebody read mail that nobody reads. Under the timer, the unit is in a failed state, systemctl --failed lists it, and monitoring can see it.
Notes
Persistent=true is the systemd equivalent of anacron: if the machine was off when the timer should have fired, it runs once at the next boot. Cron simply misses the slot, which is why a laptop's overnight jobs never run.