Triggering regular tasks with Systemd

Alarm Clock

Author(s):

Systemd can start timers that automatically perform tasks at specified times. The configuration files are known as timer units.

You might want to use your Linux system to automatically create a backup every evening and rotate the log files at regular intervals. In most distributions, time-controlled tasks are handled by the Cron daemon. But Systemd is an interesting alternative to Cron. Systemd controls the startup process of most distributions, and it can also trigger time-controlled and recurring tasks.

Service Providers

The first task is to tell Systemd which task to perform. To do this, you create a configuration file, the Service Unit. Listing 1 shows an example.

Listing 1

Service Unit

[Unit]
Description=Create a backup of the system
[Service]
ExecStart=/usr/bin/backup.sh /mnt

A service unit is a text file divided into several sections. The [Service] section is required. ExecStart= is followed by the command to be executed by the system. In Listing 1, Systemd would simply run a script that backs up the system to the /mnt directory. The [Unit] section adds some metadata. In the simplest case, Description= is followed by a description of the task.

Service Units usually tell Systemd which services to boot when the system starts. (See the article on Systemd units elsewhere in this issue.) Systemd also supports additional sections and settings. However, since the system just needs to schedule the task, these settings are not (absolutely) necessary. In particular, you can leave out the complete [Install] section.

Save the newly created service unit to /etc/systemd/system. The filename corresponds to the (internal) name of the service unit. It must be unique among all service units and end with .service, as in backup.service. Systemd can also start existing service units or service units supplied by the distribution on a time-controlled basis. In this case, simply make a note of the filename of the service file.

Tick-Tock

To avoid burning the cake to a crisp, most hobby bakers set a kitchen timer. In a similar way, you need to set a separate timer for a task you wish to assign to Systemd.

First, create a new text file in the /etc/system/system subdirectory. The text file should have the same filename as the service unit you created earlier, but it ends with .timer. In the example, the file would be named backup.timer. In Systemd speak, the file with the .timer extension is known as the timer unit. In the timer unit, you describe when the timer should "go off," at which point, Systemd will start the backup.

The structure of a timer unit is very similar to that of a service unit. As the example from Listing 2 shows, it typically consists of three sections: [Unit] is followed by general information about the timer. In Listing 2, this information would include a Description= that serves mainly as a reminder for the user. Make a note on why the timer exists and what actions it triggers.

Listing 2

Timer Unit

[Unit]
Description=Create a daily backup of the system
[Timer]
OnCalendar=*-*-* 18:15:00
Persistent=true
RandomizedDelaySec=2h
[Install]
ZWantedBy=timers.target

Current Events

In the next section, [Timer], you tell Systemd when to start the task. Make a note of this time after OnCalendar= in the notation weekday year-month-day hour:minutes: seconds. The setting OnCalendar=Fr 2018-11-30 12:00:00 tells Systemd to create the backup on Friday, November 30, 2018 at noon precisely. You can omit unnecessary information, such as the day of the week or the seconds.

Normally, you will not want Systemd to run the task once only, but repeat it. To set up a repeating event, you can simply list the corresponding days, dates, and times separated by commas. In the example from the first line of Listing 3, Systemd starts the backup November 30, 2018 at 1AM and 12 Noon.

Listing 3

Date and Time

OnCalendar=2018-11-30 01,12:00:00
OnCalendar=2018-01..12-01 01,12:00:00
OnCalendar= 2018-*-01 01,12:00:00

You can also abbreviate the number ranges with two dots .., which means that you do not have to list all the months, for example. The entry from the second line of Listing 3, tells Systemd to take action on the first day of each month. If the statement applies to all months, you can also use the wildcard * (line three).

The *-*-* entry from Listing 2 tells Systemd to run the backup every day at 18:15 in every month and every year.

Extremely Hesitant

If the computer is not running at the selected time, Systemd cannot create a backup. In Listing 2, the Persistent=true setting ensures that Systemd catches up with the task as quickly as possible in such situations. However, if several actions start simultaneously, they can slow down the system or even interfere with each other.

To prevent a traffic jam, Systemd randomly delays execution by a few seconds if necessary. The maximum number of seconds it can wait before executing is stated after RandomizedDelaySec=. Systemd interprets the number as minutes for a trailing m and as hours for an h. In Table 1, you will find all other supported time units; you can also combine these. Systemd would delay the backup by a maximum of 90 seconds if you state RandomizedDelaySec="1m 30s".

Table 1

Units Used by Systemd

Unit

Long forms

Meaning

Example

s

seconds, second, sec

second

5s

m

minutes, minute, min

minute

10m

h

hours, hour, hr

hours

2h

d

days, day

day

7d

w

weeks, week

week

2w

M

months, month

month

6M

y

years, year

year

4y

Repetitions

Systemd lets you schedule a task to occur at some recurring interval without specifying an exact time – for example, every 15 minutes or once a week. Use the OnCalendar=weekly option to start a weekly backup. In addition to weekly, you'll find options for minutely, hourly, daily, monthly, yearly, quarterly, and semiannually.

If you want to run a task 15 minutes after system startup, use the following settings instead of OnCalendar=...:

OnBootSec=15m
OnUnitActiveSec=1w

OnBootSec= specifies how many seconds after system startup Systemd should execute the task. In the example, the timer goes off 15 minutes after the system startup. The second setting, OnUnitActiveSec=, tells Systemd the time intervals at which it should repeat the task. In the example, Systemd would run the backup 15 minutes after system startup and then every week.

With both settings, you can use the units from the Table 1 and combine the information. For example, the OnBootSec="5m 30s" setting would execute the task five and a half minutes after system startup.

If a timer is based on a (calendar) date, as per Listing 2, it is known as a "Calendar Timer." If, on the other hand, a timer starts after a specified period of time relative to an event, such as a system start, Systemd refers to it as a "monotonic timer." Such timers work independently of the time zone.

The timer is not only triggered shortly after system startup, but also responds to other events listed in Table 2. As in the previous example, several settings can be combined with each other; each setting must have its own line.

Table 2

Monotonic Timers

Setting

Refers to the moment when…

OnActiveSec=

… the timer was activated.

OnBootSec=

… the computer was booted.

OnStartupSec=

… Systemd started.

OnUnitActiveSec=

… the unit that activates the timer was last activated.

OnUnitInactiveSec=

… the unit that activates the timer was last deactivated.

Relationship Helper

The systemd-analyze tool helps you figure out the correct times. If you pass it the calendar parameter, systemd-analyze converts the relative time specifications into other formats (Figure 1). The following command tells you, for example, which day of the week weekly corresponds to:

$ systemd-analyze calendar weekly
Figure 1: A timer starting weekly would execute at midnight every Monday. The next event will be in exactly five days.

By default, Systemd guarantees one-minute timer accuracy. You can therefore expect the backup not to start punctually at 6:00 pm, but at 6:01 pm. If you need greater accuracy, add the line AccuracySec=30s to the [Timer] section. The time specification determines the desired accuracy; in the example, the action would be no later than 30 seconds after the assigned date. For such time entries, you can again use the units from Table 1.

Timers also let you wake up the computer from suspend mode on a time-controlled basis. To do this, add the line WakeSystem=true to the [Timer] section. Systemd only wakes the system when it is in sleep mode and if the hardware and the BIOS/UEFI of the computer support the process. Systemd is currently unable to put the computer to sleep on a time-controlled basis.

Systemd assigns the timer unit to the appropriate service unit based on the filenames. In the example, the timer backup.timer automatically starts the command from the service unit backup.service. Alternatively, in the [Timer] section, you can explicitly specify the name of the service unit that you want Systemd to execute using the Unit= setting. This is especially useful if you want to start an existing service unit with a new timer.

Winding Up the Clock

If you want Systemd to activate the timer directly at system startup, you need an [Install] section in the timer unit. The WantedBy= setting tells which other units the timer should start with. In Listing 2, the WantedBy=timers.target setting ensures that Systemd starts the timer together with all other timers at the regular system startup time.

If you want Systemd to start the timer at startup time, you have to enable it explicitly (Listing 4, first line). Alternatively, you can start the timer manually (second line). All currently configured timers are listed by the systemctl list-timers command (Figure 2).

Listing 4

Enabling at Startup

$ systemctl enable backup.timer
$ systemctl start backup.timer
Figure 2: Systemctl displays all timers currently running. The display requires the widest possible terminal; alternatively, you can use systemctl list-timers --no-pager to output the information to the standard output.

In the table under Next, you can read when the system timer will execute the task the next time. The time remaining until then is in the Left column. Similarly, you can see under Load when systemd-timer last executed the task. How long ago that was is shown in the Passed column. Under Unit, you will find the name of the corresponding timer and thus its configuration file.

You can end the display by pressing [Q]. By default, Systemctl only presents timers that are currently enabled. You can display the inactive timers on screen by appending the --all parameter.

Snooze Button

If required, each timer can be stopped manually (Listing 5, first line) and disabled (second line). The manpage [1], which goes by the name of systemd.timer, provides explanations for all presented settings. man systemd.time provides further information on the format of dates and times and offers numerous additional examples.

Listing 5

Manual Stop

$ sudo systemctl stop my.timer
$ sudo systemctl disable my.timer

Short-Term Alarm

If you want Systemd to make a single backup in exactly 30 minutes, use systemd-run. The command looks like the first line of Listing 6. The /usr/bin/backup.sh /mnt command appended there is executed by Systemd at the specified time. Use the parameter --on-active to tell it the waiting time.

Listing 6

Examples

$ systemd-run --on-active=30m /usr/bin/backup.sh /mnt
$ systemd-run --on-calendar=weekly --unit backup.service

The time units again correspond to those in Table 1. In the example, Systemd interprets the 30m as half an hour. Alternatively, use --on-calendar= to enter a specific date. The details are again provided in the same way as in the timer unit. With appropriate time specifications such as weekly, the action can execute repeatedly.

In any case, systemd-run creates a new timer in the background without you needing to create a service file (Figure 3). If a suitable service unit already exists, you can alternatively let systemd-run launch it. To do this, simply pass in the name of the service unit using the --unit parameter. The example from the second line of Listing 6 starts the task stored in the backup.service service unit every week.

Figure 3: The timers generated by systemd-run have cryptic names that typically do not indicate the task solved by the timer.

The timers generated by systemd-run only exist temporarily. If you use the --on-active parameter, the timer disappears immediately after the action has been executed; in any case, it disappears after rebooting the system. systemd-run only creates a timer for a service unit if no suitable timer unit exists.

Conclusions

Compared to good old Cron, the timers from Systemd offer a number of benefits. Systemd is now included with most distributions. The actions can also be started independently of the timer, executed in a very specific environment, assigned to groups, and made dependent on other units.

However, as the simple example from Listing 2 shows, the configuration overhead is significantly higher for Systemd timers. A short line is all it takes with Cron, but with Systemd, you first have to write a complete timer unit. Furthermore, unlike Cron, Systemd cannot send you an email in case of an error and thus draw attention to problems. Systemd timers should therefore not replace Cron, at least not in the near future, but merely supplement it.