Using systemd timers to run things frequently (some early notes)
If you're satisfied with running something no more often than once a minute, /etc/cron.d entries are the easiest approach and what I use. But today I wound up wanting to run something more frequently. While there are various ways to do this with various degrees of hackery, it seemed like a good time to try out systemd timer units.
First we will need our .service unit, which is straightforward:
[Unit] Description=Read sensors [Service] Type=oneshot # Run your script ExecStart=/opt/cslab/generate-sensor-metrics
The skeleton of the corresponding .timer unit is:
[Unit] Description=Timer for reading sensors [Install] WantedBy=timers.target [Timer] AccuracySec=5s ... we need some magic here ...
insures that systemd runs our service more or less when we ask it
to, instead of delaying. You may want to be narrower here, for
example saying '1s' as the required accuracy.)
The remaining thing we need is something to tell systemd that, for
example, we want this to run every 30 seconds. There are at least
First, we can use
to set a systemd time specification to
run, say, on :05 and :35 of every minute:
(Another option for how to specify this sort of time is '
which means more or less what it would in cron.)
This is much like cron time specifications except it allows us to
go down to seconds instead of stopping at minutes the way that cron
does. After looking at things and writing this entry, I've come
to feel that using
OnCalendar is your best and simplest option
if the time intervals you want divide evenly into a minute (eg
things like 'every 30 seconds', 'every 15 seconds', or 'every 10
seconds') and you're not allergic to always running your script at
Alternately we can try to say 'activate this every 30 seconds', or
whatever number of seconds you want (including numbers that
deliberately don't evenly divide into minutes, such as 31 seconds).
Systemd doesn't have a straightforward way of expressing this that
I can see; instead, you get to say 'do this 30 seconds after <some
events>', and then you pick the events. You need at least two events;
one to start things initially, when the system boots or you start
the timer, and one to make it repeat. I currently feel that the
best single option for a starting event is
because that covers all of the various cases where the timer gets
activated, not just when the system boots. If you stop the timer
for a while and then do '
systemctl start <thing>.timer', this
will kick it off.
There are two options for getting things to repeat, OnUnitActiveSec and OnUnitInactiveSec, which define delays from when the unit started and when the unit stopped respectively. I believe that if you want there to be a 30 second delay between successive runs of your script, then you want to use OnUnitInactiveSec. On the flipside, if you want things to tick every 30 seconds no matter how long the script took, you want OnUnitActiveSec.
So a plausible [Timer] section is:
[Timer] AccuracySec=5s OnActiveSec=30s OnUnitActiveSec=30s
You could set 'OnActiveSec' to a smaller value, since all it is there for is to trigger the initial service unit activation that then starts the every 30 second ticker. Generally, the timer will be activated as the system boots, so you'll start ticking 30 seconds after that.
In all cases, I believe that using a systemd timer and service unit means that only one copy of your script will ever be running at one time. Timer units have the effect of activating your service unit, so if your service unit is already (or still) active, systemd does nothing rather than activating a second copy.
One of the downsides of using systemd timers for this is that you get a certain amount of log spam from it. Every time the timer unit starts your service unit, you'll most likely get three log lines:
Starting Read sensors <thing>.service: Deactivated successfully. Finished Read sensors
Using crontab generally gets you only one log line per invocation. On the other hand, your (systemd) logs may already be getting flooded from other things; this is definitely the case on some of our machines.
PS: One reason to pick non-divisible numbers of seconds, such as
31, is to insure that you never synchronize with something else
that happens either on fixed seconds or at some other fixed interval,
like 'every 15 seconds'. However, see the
timer unit settings for other potential options here.