Skip to content
Search Rocky Linux

    Browse this documentation

    Rocky 10: replacing cron with systemd timers

    In a Rocky Linux 10.2 privileged container (systemd 257, running as PID 1 inside the container): wrote lab-tick.service + lab-tick.timer, ran systemctl enable --now, list-timers, a manual start, then disable and cleanup. Log: plans/content-expansion/evidence/logs/rocky-systemd-timers.log.

    The container shares the host kernel (5.14); systemd 257 is genuine EL10 userspace. Anything about kernel scheduling belongs on a real host.

    • Output goes to the journal (journalctl -u), no manual redirection;
    • You can declare dependencies (After=, Requires=) that match boot ordering;
    • Persistent=true runs a missed job once after boot;
    • Accuracy and jitter are controllable (AccuracySec, RandomizedDelaySec).

    cron stays smaller and more portable; the choice depends on whether you need those properties.

    /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
    [Unit]
    Description=lab tick timer
    [Timer]
    OnCalendar=*:0/1
    Persistent=true
    [Install]
    WantedBy=timers.target

    The timer and service must share a name (lab-tick.timer triggers lab-tick.service). Type=oneshot fits scripts that run and exit.

    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:48:00 UTC 2s - - lab-tick.timer lab-tick.service

    NEXT is the next trigger and ACTIVATES points at the paired service. Those two columns are how you confirm a timer works, no guessing required.

    Terminal window
    sudo systemctl start lab-tick.service
    tail -2 /var/log/lab-tick.log
    2026-10-20T11:47:58Z

    Starting the service does not change the timer schedule; it validates the script itself.

    Terminal window
    sudo systemctl disable --now lab-tick.timer
    sudo rm -f /etc/systemd/system/lab-tick.{service,timer} /usr/local/bin/lab-tick.sh
    sudo systemctl daemon-reload

    disable --now stops the timer and removes the symlink under timers.target.wants (the observed output was Removed '.../lab-tick.timer').

    • Enabling only the service: the timer never starts and never appears in list-timers;
    • Mismatched names: foo.timer only triggers foo.service;
    • Wrong OnCalendar: *:0/1 means every minute, not every hour; check with systemd-analyze calendar.
    Terminal window
    sudo tee /etc/systemd/system/lab-tick.service >/dev/null <<'EOF'
    [Unit]
    Description=lab tick
    [Service]
    Type=oneshot
    ExecStart=/bin/date
    EOF
    sudo tee /etc/systemd/system/lab-tick.timer >/dev/null <<'EOF'
    [Unit]
    Description=lab tick timer
    [Timer]
    OnCalendar=*:0/1
    [Install]
    WantedBy=timers.target
    EOF
    sudo systemctl daemon-reload
    sudo systemctl enable --now lab-tick.timer
    systemctl list-timers lab-tick.timer
    systemd-analyze calendar '*:0/1'
    Normalized form: *-*-* *:00/1:00
    Next elapse: Tue 2026-10-20 11:50:00 UTC
    From now: 53s left

    Checks:

    1. NEXT in list-timers is within 60 seconds
    2. systemd-analyze calendar '*:0/1' prints Next elapse: and Iteration
    3. systemctl status lab-tick.timer shows active (waiting)
    4. After disable --now, list-timers no longer lists it

    常见问题

    The timer fired but the script did not run — where do I look?

    Check systemctl status <name>.timer for active, then journalctl -u <name>.service for the invocation; if the names do not match, the timer never triggers that service.

    How many times does Persistent=true catch up?

    Once — missed windows are merged into a single run, not replayed per occurrence, which is usually what backup jobs want.

    Is the syntax the same on EL9?

    Timer unit syntax is identical; EL10 ships systemd 257 versus roughly 252 on EL9, so check man systemd.timer for newer OnCalendar extensions.