Skip to content
Search AlmaLinux

    Browse this documentation

    AlmaLinux 10: moving from cron to systemd timers

    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.

    crontabOnCalendar
    * * * * **:0/1 (every minute)
    0 * * * *hourly or *-*-* *:00:00
    30 2 * * **-*-* 02:30:00
    0 3 * * 1Mon *-*-* 03:00:00
    @reboota 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.

    /etc/systemd/system/lab-tick.service
    [Unit]
    Description=lab tick
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/lab-tick.sh
    /etc/systemd/system/lab-tick.timer
    [Timer]
    OnCalendar=*:0/1
    Persistent=true
    [Install]
    WantedBy=timers.target
    Terminal window
    sudo systemctl daemon-reload
    sudo systemctl enable --now lab-tick.timer
    systemctl list-timers --all | grep -E "lab-tick|NEXT"
    NEXT LEFT LAST PASSED UNIT ACTIVATES
    Tue 2026-10-20 11:33:00 UTC 45s - - lab-tick.timer lab-tick.service

    Same-name rule: lab-tick.timer only triggers lab-tick.service.

    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.

    Terminal window
    systemctl status lab-tick.timer --no-pager
    systemctl list-timers --all | grep lab-tick
    journalctl -u lab-tick.service --no-pager | tail -5
    systemd-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.

    • 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”.
    • 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.

    Original cron: 30 2 * * * /usr/local/bin/backup.sh

    Terminal window
    sudo tee /etc/systemd/system/lab-backup.service >/dev/null <<'EOF'
    [Unit]
    Description=lab backup
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/backup.sh
    EOF
    sudo tee /etc/systemd/system/lab-backup.timer >/dev/null <<'EOF'
    [Timer]
    OnCalendar=*-*-* 02:30:00
    Persistent=true
    [Install]
    WantedBy=timers.target
    EOF
    sudo systemctl daemon-reload && sudo systemctl enable --now lab-backup.timer
    systemd-analyze calendar '*-*-* 02:30:00'
    systemctl list-timers lab-backup.timer

    Checks:

    1. systemd-analyze calendar reports tomorrow 02:30
    2. list-timers lists lab-backup.timer with the right NEXT
    3. systemctl status shows active (waiting)
    4. A manual systemctl start lab-backup.service runs 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.