AlmaLinux 10: moving from cron to systemd timers
Test scope
Section titled “Test scope”In an AlmaLinux 10.2 privileged container (systemd 257): created lab-tick.service/lab-tick.timer, ran enable --now, list-timers, a manual start, then disable. Log: plans/content-expansion/evidence/logs/alma-systemd-timers.log.
The container shares the host kernel (5.14); systemd is genuine EL10 userspace, so kernel-related conclusions need a real host.
crontab versus OnCalendar
Section titled “crontab versus OnCalendar”| crontab | OnCalendar |
|---|---|
* * * * * | *:0/1 (every minute) |
0 * * * * | hourly or *-*-* *:00:00 |
30 2 * * * | *-*-* 02:30:00 |
0 3 * * 1 | Mon *-*-* 03:00:00 |
@reboot | a oneshot service with WantedBy=multi-user.target |
systemd-analyze calendar '<expression>' translates an expression into the next elapse. Three rows above (*:0/1, *-*-* 02:30:00, Mon *-*-* 03:00:00) were verified on EL10 with output containing Normalized form and Next elapse; hourly and @reboot are syntax mappings not executed individually.
The two files and enabling them
Section titled “The two files and enabling them”[Unit]Description=lab tick[Service]Type=oneshotExecStart=/usr/local/bin/lab-tick.sh[Timer]OnCalendar=*:0/1Persistent=true[Install]WantedBy=timers.targetsudo systemctl daemon-reloadsudo systemctl enable --now lab-tick.timersystemctl list-timers --all | grep -E "lab-tick|NEXT"NEXT LEFT LAST PASSED UNIT ACTIVATESTue 2026-10-20 11:33:00 UTC 45s - - lab-tick.timer lab-tick.serviceSame-name rule: lab-tick.timer only triggers lab-tick.service.
Persistent: jobs missed while powered off
Section titled “Persistent: jobs missed while powered off”Persistent=true runs a missed job once after boot, not once per missed occurrence. It relies on the timer’s stamp files under /var/lib/systemd/timers/ (observed present: drwxr-xr-x root root), so do not wipe that directory casually.
That suits backups; for jobs that must run exactly on the hour, set AccuracySec=1s and accept that missed is missed.
Debug order when it never fires
Section titled “Debug order when it never fires”systemctl status lab-tick.timer --no-pagersystemctl list-timers --all | grep lab-tickjournalctl -u lab-tick.service --no-pager | tail -5systemd-analyze calendar '*:0/1'The four steps confirm: is the timer active, does a schedule exist, was the service invoked, does the expression mean what you think. Check the timer before the service — doing it the other way usually misdiagnoses a script problem.
Accuracy and jitter
Section titled “Accuracy and jitter”AccuracySec=1s: tightens the default one-minute window (more punctual, slightly more wakeups);RandomizedDelaySec=30s: spreads triggers across a fleet;OnBootSec=/OnUnitActiveSec=: relative timers such as “ten minutes after boot”.
Common traps
Section titled “Common traps”- Enabling only the service: the timer never starts;
- Mismatched names: the timer cannot find its service;
- OnCalendar time zone: follows the system zone by default; confirm it when deploying across zones.
Practice: migrate one cron line
Section titled “Practice: migrate one cron line”Original cron: 30 2 * * * /usr/local/bin/backup.sh
sudo tee /etc/systemd/system/lab-backup.service >/dev/null <<'EOF'[Unit]Description=lab backup[Service]Type=oneshotExecStart=/usr/local/bin/backup.shEOFsudo tee /etc/systemd/system/lab-backup.timer >/dev/null <<'EOF'[Timer]OnCalendar=*-*-* 02:30:00Persistent=true[Install]WantedBy=timers.targetEOFsudo systemctl daemon-reload && sudo systemctl enable --now lab-backup.timersystemd-analyze calendar '*-*-* 02:30:00'systemctl list-timers lab-backup.timerChecks:
systemd-analyze calendarreports tomorrow 02:30list-timerslistslab-backup.timerwith the right NEXTsystemctl statusshowsactive (waiting)- A manual
systemctl start lab-backup.serviceruns the script
常见问题
Can timers and cron coexist?
Yes, but never configure the same job twice or it runs twice. During migration, disable the cron entry first, enable the timer, then watch one full cycle of logs.
How do I confirm Persistent actually caught up?
Look for a journal entry right after boot in journalctl -u <service>, and for the corresponding stamp file under /var/lib/systemd/timers/.
Which time zone does OnCalendar use?
The system time zone by default. On containers or hosts across zones, check timedatectl first and then write the expression to avoid the classic eight-hour offset.
Next steps
Section titled “Next steps”- Log rotation: logrotate in practice
- Reboot policy: Reboot policy
- Firewall rules: firewalld rich rules