Introduction
As a sysadmin you will face countless times in which you need to schedule tasks to automate process. The de facto solution is to use cron and crontab, in this tutorial you will meet the built in solution in the systemd service manager called timer.
Requirements
- Any Linux machine with
systemd
as service manager, ie Ubuntu, Centos, Fedora, Debian, etc.
Differences with cron
In the following the differences between systemd.timers
and cron
are presented. Note that they are not arranged in advantages or disadvantages because each sysadmin should choose tools according to experience and preferences.
- Each task has its own service on systemd.
- Each task needs two files, one service and the actual timer.
- Full access ot the systemd ecosystem.
- Tasks are logged in the systemd journal.
- There is no
mailto
equivalent function for sending emails at job failure.
Overview of the process
In order to create a task with systemd.timers
you have to do 3 simple steps in that specific order. If you are used to manage custom systemd services this information will not be that new for you, otherwise please review this process.
- Creating a service file: They are services files, they end with
.service
. These ones describe how the service should be treated. - Creating the timer file: They end with
.timer
. They are also unit files, but you configure how and when the timer activates. - Activating the timer: After having done your files you can start your timer with the help of
systemctl
.
Note: You should always have a name matching pair of files, one with the .service
ending and another one with the .timer
ending. Any timer without proper names will fail because the timer file is the one that activates and then controls the service file. The name of your service is pointed in the timer file, so it is better to share the name to ease maintenance operations.
Types of timers
When scheduling tasks we need to ensure that our tool can respond to two situations, tasks at certain date and tasks at intervals of time. Fortunately timers can accomplish this using an easy to use syntax.
- Realtime timer: These are the ones that activate on a calendar date. You use the
OnCalendar
option to trigger this type of timers. - Monotonic timer: They trigger after a span of time, they can start with the system and other events, but it is recommended to delay their activation to prevent overloading the system. You normally use a combination of
OnBootSec
andOnActiveSec
.
Creating tasks
After having reviewed the overall information of timers, we can start to create examples, one per type in the following part.
Note: Both .service
and .timer
files must be stored in /etc/systemd/system/
.
Create required bash file
Two bash files are created in our home directory, these are the files that we are going to schedule in each of our tasks.
Preparing First file
echo "ping -c 3 google.com >> /home/YOUR_USER/ping_task1.txt" >> /home/YOUR_USER/task1.sh
chmod +x /home/YOUR_USER/task1.sh
Preparing Second file
echo "ping -c 3 google.com >> /home/YOUR_USER/ping_task2.txt" >> /home/YOUR_USER/task2.sh
chmod +x /home/YOUR_USER/task2.sh
Note: systemd.timer
is not a substitute of Bash, you have to group your instructions in scripts for better maintenance.
Example 1 Realtime or wallclock timer
The first example should accomplish this: Scheduling a ping to be executed after 20 minutes of the user's real time, then dump its results to a file.
In the task1.service
file the service is configured, it is a simple file with its own description and the tasks to execute under the Service
part.
[Unit]
Description=Vultr wallclock timer example
[Service]
ExecStart=/bin/bash /home/YOUR_USER/task1.sh
In the task1.timer
file the timer is configured, as every unit file we should start with the Unit
section, after that the rest of the configuration is written.
For the Timer
section we are setting OnCalendar
, which is the exact date of activating, it follows an special syntax that you can review some paragraphs below this. The RandomizedDelaySec
is just a security matter to randomize activation time, this in order to prevent many services activating in the same time with the risk of running out of memory. Unit
under the Timer
section corresponds to the name of the service file that was created in the last step, in other words it is task1.service
.
The Install
section can be copied over here, because it is telling that we are putting this under the control of service.timer
.
[Unit]
Description=Run wallclock example 20 minutes after been activated
[Timer]
OnCalendar=YOUR_TIME
RandomizedDelaySec=1min
Unit=task1.service
[Install]
WantedBy=timers.target
In this file YOUR_TIME
should be a valid structure with the form: DayOfWeek Year-Month-Day Hour:Minute:Second
for example OnCalendar=Wed,Sun *-*-9..14 12:00:00
which translates to Execute every Wednesday and Sunday of all months in all years if they are between day 9 and 14 at 12 hours, time is written in a 24h format. With this you can build your date to activate your task 20 minutes later than your actual date. If you are unsure about your system's time type the date
command in your terminal, you will get the actual system's time with this.
Note: in the OnCalendar
option there is special syntax, items separated by ,
are treated as lists, ranges are made using ..
and they are inclusive, the wildcard *
can represent any accepted value of the position where it is placed.
With this the first task can be activated, take a look that we are manipulating the .timer
file, not the .service
one:
systemctl enable task2.timer
systemctl start task2.timer
Example 2 Monotonic timer
The second example should accomplish this: Scheduling a ping every 5 minutes from boot up time, delay its first activation time by 5 minutes, then every activation should be after 5 minutes.
The task2.service
structure is identical to the first example. Do not forget to write a meaningful description to you, also do not forget to point the correct script int the Service
section.
[Unit]
Description=Vultr monotonic timer example
[Service]
ExecStart=/bin/bash /home/YOUR_USER/task2.sh
The task2.timer
is slightly different, it uses two operations. OnBootSec
tell us that the tasks are activated after an specific time of booting up our system in this case it is 5 minutes after booting. OnUnitActiveSec
describes the span of time between activations, in this case it is 5 minutes between consecutive activations. The rest of the file is already explained in the first example.
[Unit]
Description=Run monotonic timer every 5 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=task2.service
[Install]
WantedBy=timers.target
There are many ways to create monotonic timers, their difference is the starting point. OnActiveSec
is relative to the moment the timer is activated. OnBootSec
is relative to the time the system booted up. OnStartupSec
is relative to the time systemd
was first started. OnUnitActiveSec
is relative to the last time the timer to be activated was last activated. OnUnitInactiveSec
is relative to the las time the timer to be activated was last deactivated. You can abuse wildcards and lists in the OnCalendar
option to emulate this behavior, but it is not recommended because the date definition can become hard to read and maintain.
Then then the second task is activated:
systemctl enable task2.service
systemctl start task2.service
At this point reboot your computer so you second task is ready to function.
After a succesful reboot, wait for your timers to activate, then go to you home folder and list all your files. If everything went fine you should see your bash files along the files that contain the result of the ping done in the timer:
YOUR_USER@YOUR_HOST:~# ls
ping_task1.txt ping_task2.txt task1.sh task2.sh
The last thing to corroborate that our tasks run successfully is reading their content with the command cat
, in this case we are seeing the content of the first task, you can repeat it to list the content of the second task, just beware that its content may be larger due to constant activation and constant append. If you see the content of the ping then everything is perfect.
YOUR_USER@YOUR_HOST:~# cat ping_task1.txt
PING google.com (216.58.216.142) 56(84) bytes of data.
64 bytes from sea15s01-in-f142.1e100.net (216.58.216.142): icmp_seq=1 ttl=57 time=0.246 ms
64 bytes from sea15s01-in-f142.1e100.net (216.58.216.142): icmp_seq=2 ttl=57 time=0.417 ms
64 bytes from sea15s01-in-f142.1e100.net (216.58.216.142): icmp_seq=3 ttl=57 time=0.331 ms
--- google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.246/0.331/0.417/0.071 ms
Reaching this point we can create basic timers with any time configuration needed, but still we need to learn how manage them.
Management
As stated above, timers are heavily tied to the systemd ecosystem, so we can take advantage of systemd tools.
Listing all timers
The first step to ensure that our timers are working is using the command systemctl list-timers
, we should see them listed under the Unit
column.
YOUR_USER@YOUR_HOST:~# systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
n/a n/a Wed 2018-04-11 18:00:42 UTC 1h 59min ago task1.timer task1.service
Wed 2018-04-11 20:02:07 UTC 2min 23s left Wed 2018-04-11 19:57:07 UTC 2min 36s ago task2.timer task2.service
Thu 2018-04-12 05:28:39 UTC 9h left Wed 2018-04-11 07:50:31 UTC 12h ago apt-daily.timer apt-daily.service
Thu 2018-04-12 06:28:47 UTC 10h left Wed 2018-04-11 06:17:40 UTC 13h ago apt-daily-upgrade.timer apt-daily-upgrade.service
Thu 2018-04-12 18:13:38 UTC 22h left Wed 2018-04-11 18:13:38 UTC 1h 46min ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Mon 2018-04-16 03:56:05 UTC 4 days left Wed 2018-04-11 18:31:49 UTC 1h 27min ago snapd.refresh.timer snapd.refresh.service
** Note: To list all timers including the inactive ones, append the --all
option to the command.**
If your task1 has already triggered you will see n/a
in the columns Next
and Left
, the first expresses the date of the next trigger and the second the remaining time to be triggered.
Checking the status of your timers
The second thing to ensure wellbeing is checking the status of each timer. To access it just use systemctl status YOUR_TASK.timer
, in this case the second timer is checked, everything seems ok because it is active and waiting. If there was an error you could see it in this part.
YOUR_USER@YOUR_HOST:~# systemctl status task2.timer
● task2.timer - Run monotonic timer every 5 minutes
Loaded: loaded (/etc/systemd/system/task2.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Wed 2018-04-11 17:58:37 UTC; 2h 7min ago
Apr 11 17:58:37 vultr.guest systemd[1]: Started Run foo weekly and on boot.
Something to note is that when the first task is triggered its status will go from waiting
to elapsed
but will remain active because its job is to trigger only one time.
Inspecting logs
In this part we are checking again the second timer. One thing to note is that both logs files can be checked, the timer and the service. The command is journalctl -f -u YOUR_UNIT
.
As we can see in the logs, the timer file will only be called once, in its activation time.
YOUR_USER@YOUR_HOST:~# journalctl -f -u task2.timer
-- Logs begin at Wed 2018-04-11 17:58:36 UTC. --
Apr 11 17:58:37 vultr.guest systemd[1]: Run monotonic timer every 5 minutes.
Remember that the service file is the one to be controlled, that is why we see and entry for each activation.
YOUR_USER@YOUR_HOST:~# journalctl -f -u task2.service
-- Logs begin at Wed 2018-04-11 17:58:36 UTC. --
Apr 11 19:25:52 vultr.guest systemd[1]: Started Vultr monotonic timer example.
Apr 11 19:31:04 vultr.guest systemd[1]: Started Vultr monotonic timer example.
Apr 11 19:36:08 vultr.guest systemd[1]: Started Vultr monotonic timer example.
Apr 11 19:41:36 vultr.guest systemd[1]: Started Vultr monotonic timer example.
The absence of content of both logs means that something not desired is happening, before jumping to conclusions check that your timers are activated.
Enabling and starting
To manage enabling and starting our timers systemd syntax is used: enable
to activate on boot, disable
to remove this activation, start
to initiate the timer right now without boot activation, stop
to cancel a timer in execution, if its enabled it will activate at the next boot or when we start it again with start
.
Conclusion and further reading
You dealt with a lot of information this time. The benefits of this are increasing your systemd knowledge and getting to know a simpler way of scheduling tasks in the Linux ecosystem. At first timers appear to be more complicated than should be, after all with cron you only have to append your task to the crontab file and let it execute itself. But basic things like logging can become cumbersome if you are jumping distributions. Timers resolve that and other problems by letting systemd doing the heavy lifting. The next step in your journey would we studying the unit file definitions to expand your knowledge in things like controlling starting and ending events or including other systemd elements as requirements.