systemd Timer – a Better Cron Replacement

As a Linux user you’re probably familiar with cron. It has worked as the go-to Unix time-based job scheduler for many years. Now many users are seeing Systemd timers begin to replace cron’s dominance.

Systemd is the new standard for init systems, intended to replace the aging SysV init system. Since then it has added a ton of features that start to encroach on other Linux utilities. Systemd timers are one of those features.

Systemd timers are a way of running service units based on time. These timer units have quite a bit of flexibility, leading them to be a potential replacement for cron.

Traditional cron has all jobs for a user in a single file called the crontab. This has a few problems with configuration management.

The first issue with cron is logging. By default, any output from a cronjob is mailed to support logging. In systemd, the jobs are presented as systemd units, so they are logged to the syslog. This enables any integration that would normally be possible using journalctl for instance. Logging to the syslog also means that the powerful features of journalctl can be used. For example, let’s assume that an admin is investigating a job that is suspected to have crashed the server 2 reboots ago. The admin can get granular access through a command like journalctl –boot=-2 –unit=thejob.service.

Another common issue with cron is that similarly scheduled jobs need a gap between them to prevent overloading the system. In traditional cron, this requires the administrator to manually place the jobs far enough apart so that they will probably not be run at the same time. With systemd timers, a “Conflicts” section can be added to ensure that this does not happen. Furthermore, a randomized delay can be added with RandomizedDelaySec section. This adds a randomized delay to the start of the job so that similarly scheduled jobs are further separated.

Systemd timers do not only support time of day scheduling; they also support relative scheduling, allowing for jobs to be scheduled relative to other events such as boot or timer activation. This is done by specifying a relative time like 15min or 1y 12month on the relevant Sec entry such as OnBootSec or OnUnitActiveSec.

Systemd timers also have more specific specification abilities, including precision down to the second and specification from the end of months allowing for more flexibility in time specifications.

Since timers are also services, they get their own cgroup, meaning they can get all the features that come with it such as memory and cpu limits, and even more features such as IP accounting or IP blocklists.

Systemd Timer Implementation

Systemd timers are implemented in two files per job: one file describing the timing of the job, and one describing the actual job to be executed. The timing is in a .timer file, and the job is in a .service file. Timer files are special within systemd, but the .service files associated with them are written in the same way as any other .service file.

For example, let’s assume that you want to launch a backup script of your apache website every day.

Create the /var/www/backup directory:
# mkdir /var/www/backup

Create the /var/www/backup/backup.sh file and paste the following lines:

#!/bin/bash
DAYMONTH=`date “+%d”`
/bin/tar –selinux -czvf /var/www/backup/backup-$DAYMONTH.tgz /var/www/html &>/dev/null

Make it executable:
# chmod +x /var/www/backup/backup.sh

Create the /usr/lib/systemd/system/backup.service file and paste the following lines:

[Unit]
Description=Backup of my apache website

[Service]
Type=simple
ExecStart=/var/www/backup/backup.sh

[Install]
WantedBy=multi-user.target

 

Timer Creation

Create the /usr/lib/systemd/system/backup.timer file and paste the following lines:

[Unit]
Description=Execute backup every day at midnight

[Timer]
OnCalendar=*-*-* 00:00:00
Unit=backup.service

[Install]
WantedBy=multi-user.target

Some other options like OnCalendar are available:

  • OnActiveSec defines a timer relative to the moment the timer itself is activated.
  • OnBootSec defines a timer relative to when the machine was booted up.
  • OnStartupSec defines a timer relative to when systemd was started.
  • OnUnitActiveSec defines a timer relative to when the unit the timer is activating was last activated.
  • OnUnitInactiveSec defines a timer relative to when the unit the timer is activating was last deactivated.
  • AccuracySec defines the time window within the timer is scheduled to elapse (1min by default).
  • Persistent,a boolean, if set to true, the time when the service unit was last triggered is stored on disk. This information is then used on next reboot to possibly execute overdue timer events, that could not take place because the system was powered off.
  • WakeSystem, a boolean, if set to true, timers configured this way will cause the system to resume from system suspend.
  • RandomizedDelaySec, schedules an event to occur later by a random number of seconds to spread workload over a longer time period and avoid several events executing at the same time

Execution

Activate at boot and start the backup timer to get your website backed up every day:
# systemctl enable backup.timer
# systemctl start backup.timer

To check if the backup timer is enabled, type:
# systemctl is-enabled backup.timer

To check if the backup timer is running, type:
# systemctl is-active backup.timer

If you want to run the backup script at any time, type:

# systemctl start backup

If you decide to change the backup frequency, after modifying the OnCalendar value, don’t forget to type:
# systemctl daemon-reload

To get some information about our backup timer, type:
# systemctl list-timers backup*