Sub-Minute Job Execution with Systemd Timers
Sometimes there’s a small job that needs to be run every X seconds. But having
a daemon running calls sleep(3)
is either
overkill or you’re too lazy to implement starting/stopping/signal handling.
Cron only has a one-minute accuracy, so that won’t help in this case. Fortunately, systemd has the possiblity to run services at configured times or with a monotonic interval using timer units.
[Unit]
Description=A job that stores the time
[Service]
Type=oneshot
ExecStart=/usr/local/bin/foo.sh
/etc/systemd/system/foo.service
[Unit]
Description=Runs every 15 secs
[Timer]
OnActiveSec=0 # Run when activated
OnUnitActiveSec=15 # Run every 15 seconds
AccuracySec=500msec # Don't delay too much
[Install]
WantedBy = multiuser.target
/etc/systemd/system/foo.timer
#!/bin/sh
date >> /tmp/timestamp
/usr/local/bin/foo.sh
Enable and start the timer: systemctl enable --now foo.timer
and lo and behold:
Wed Jun 15 16:26:44 CEST 2016
Wed Jun 15 16:27:00 CEST 2016
Wed Jun 15 16:27:15 CEST 2016
Wed Jun 15 16:27:31 CEST 2016
Wed Jun 15 16:27:46 CEST 2016
Wed Jun 15 16:28:02 CEST 2016
/tmp/timestamp
Note that the timestamps are not exactly 15 seconds apart. This is because AccuracySec
is set to half a second. Systemd attempts to limit the number of wake ups and to
schedule timers simultaniously. For a more precise interval, AccuracySec
can be
set to 1us
.
An advantage of this approach (compared to to cron) is the fact that the
stdout/stderr output of foo.service
goes directly to the journal. This allows
foo.sh
(or whatever script used) to be extremely simple.
The Arch Linux wiki on systemd timers has a good section on using systemd timers as a replacement for cron, including sending emails on job failure.