One of the changes systemd brought in was a new way to schedule jobs, with more finesse than cron. Some Linux distributions no longer ship cron. It’s time to check out systemd timers.

Why systemd Timers Are Replacing cron

The origins ofcrondate all the way back to 1975, in Version 7 Unix. Its dependability soon made it a favorite tool for scheduling tasks to run at specified dates and times. Admittedly, its syntax is pretty quirky. If you don’t use it frequently, you’ll probably need to look up the finer points each time you want toschedule a job.

In cron schedules, days and months are numbered starting at one. The days of the week, however, are numbered from zero to six, for Sunday through to Saturday. And on some systems, seven means Sunday, too. But, as quirky as this might be, it works.

Listing the configured systemd timers

The systemd service manager brought much more to the table than a simple replacement for the init boot manager. Part of what it delivered was a modern replacement for cron, in the form of systemd timers. These offer more flexibility than cron does, and without the need for another external utility. They’re built right into all systemd distributions.

That means timers behave the same way on all systemd installations. There are many versions of cron and cron-like substitutes. If you need to have standardization across a number of computers, systemd makes your life easier. The same timers will run the same way on all of them. In fact, some systemd-based distributions no longer ship cron as part of their standard offering.

Running the geek-timer.sh script and verifying it writes to the logfile

Not surprisingly, the Red Hat-derived distributions includingFedoradon’t ship cron, because systemd is aRed Hatinitiative. Arch and its derivatives don’t include cron, but that’s probably more to do with them providing such a minimal distribution that you populate with applications to suit. Other distributions, such as Solus, don’t see a need to include cron either. Of course, you could install cron on any distribution you like, but there’s no compelling argument to do so.

Related:Why Linux’s systemd is Still Divisive After All These Years

How systemd Timers Work

With systemd timers, you need to create two files. One is aservicefile. When the service runs, it launches your process for you. So the service file needs to know about your target process.

The second file you need to create is atimerfile. This determines when the service is launched. So the timer file needs to know about your service file.

Using systemctl status to show the status of our new timer

Timers can bereal-timeormonotonic. Real-time timers are triggered by calendar events. Monotonic timers are triggered at some duration after a system event, such as booting. Log entries are added to the system journal for timer events, which can help with debugging.

You can list the timers on your computer by using the status option of the systemctl command. Several system timers are created automatically, so even if you haven’t created any timers, there will be output to this command.

Enabling and starting the new timer with the systemctl command

Each description contains the following information:

Because timers are actually time-controlled services, we can use the systemctl command to control them.

Creating a Simple systemd Timer

The written word is a static medium, making it difficult to illustrate a process being triggered at a specific time. What we’ll do is create a script that’ll be launched by our new timer, and have it write a timestamp to a logfile. That’ll tell us our service is working, and when it was last triggered.

We’ll usethe date commandto generate the timestamp, and we’ll redirect it to a file called “timer.log” in our home directory.

The status of the timer before the five minute post-boot period has expired

We’ll create the script in the “/usr/local/bin/” directory. We’re using the “gedit” editor, but you can use whichever editor you prefer.

Copy these lines into your editor, save the file as “geek-timer.sh”, and close your editor.

The status of the timer once it has reached the repeating every minute phase

We’ll need to make our script executable.

Let’s just check that our script does what it is meant to.

That verifies that our script executes as expected and puts a timestamp into the “timer.log” file.

The contents of the timer logfile after about ten minutes of running

Now we’ll create a service file to define the service we want to have launched when the timer is triggered.

Copy these lines to your editor, save the file as “/etc/systemd/system/geek-timer.service”, and close your editor.

The “[Unit]” section contains two lines. The “Description=” line is a simple one-liner that says what your service is for. The “Requires=” line indicates that this service relies on the “geek-timer.timer” timer file. We’ll create this file next.

There’s a little bit more in the “[Service]” section. The “Type=” is “simple”, meaning this is a basic service. Other options include “oneshot”, which would mean the service ran once only.

The “ExecStart=” line indicates which process the service should start. This is pointing to our script that we created earlier.

The “User=” line defines which user should run the command. Without this, the process would be launched by root.

Now we’ll create the timer file. This defines when the service is launched. It’s good practice to use the same base name for the server and timer files, with different extensions.

Copy these lines to your editor, save the file as “/etc/systemd/system/geek-timer.timer”, and close your editor.

The “[Unit]” section contains a “Description=” line of text. The “[Timer]” section contains three settings. The “Unit=” line indicates which service should be launched when this timer triggers. The “OnBootSec=” line tells the system to launch the service five minutes after the computer boots. The “OnUnitActiveSec=” line tells the timer to launch the service one minute after it last activated.

In other words, five minutes after the computer is booted, the service will launch. The service will then repeat with an interval of one minute.

In the “[Install]” section, we’ve include a “WantedBy=” line that specifies “timers.target.” The “timers.target” is a special target unit that sets up all timer units that are active after boot, and is suitable for all basic systemd timers.

We can use the systemctl status command to look at our new timer.

There are no errors reported, which is good. It is inactive because we haven’t started the service. Even if we reboot now, our service and timer won’t be enabled. Let’s start and enable our timer.

I rebooted the test computer to see if the five-minute grace period after boot-up was respected, and checked its status once more.

This shows the PC booted at 12:18, and our timer is going to be triggered at 12:23. Our requested five minutes after boot option is being handled correctly. I waited for the five minutes to expire and then quickly ran the same command.

We can see that the trigger time has moved on one minute from 12:23 to 12:24. This means we’re now into the “repeating every minute phase” of our timer.

Checking our logfile a few minutes later, shows the initial trigger time of 12:23, then subsequent launches occur atabouta minute apart.

Related:How to List Linux Services With systemctl

Fine Tuning the Timings

The trigger times of repeating events are slightly fuzzy. That’s why I said the events in the logfile areaboutone minute apart. There’s a small random element added to the trigger time to verify that timers that are scheduled to trigger at precisely the same time are actually triggered in a staggered fashion. Usually, for tasks like starting a backup or other system housekeeping activities, that’s accurate enough.

If you need to have a tighter resolution, you can use microsecond timing. Adding this line to the “[Timer]” section of your timer file sets the system to use a one-microsecond resolution.

These are the accuracy settings you’re able to use, and how you can refer to them.

To have a timer trigger at a particular time and date is achieved using the “OnCalendar” setting. This goes in the “[Timer]” section of the timer file. The general format is:

DayOfTheWeek is optional. Any of the other values be replaced by an asterisk ‘*’ to mean “every”, like every minute or every hour. You can use names or numbers for the days and months, and comma-separated lists to represent selections of values. Ranges of values are indicated by using two periods “..” to separate the start and values of a range.

This would set a timer to trigger at 01:15 on the first Friday of each month.

This would run a process at 19:00 every day.

A timer can have more than one trigger time set. This would run a process at a different time on business days than on the weekend.

Thesystemd time man pagefull description of time formats and many useful tips and tricks.

Great Flexibility and Ease of Use

Much of the flexibility of systemd timers resides in the way you can cater for odd-ball calendar events. For example, to set a timer to trigger at 15:00 on all days apart from Fridays, you can use this format:

By combining comma-separated lists and ranges you’ll find it easy to create real-time triggers for all manner of complicated requirements.

Once you’ve got the idea that you create a service to launch your process, and a timer file to govern the launching of the service, you’re 90 percent of the way to understanding systemd timers. The last 10 percent is embracing the graceful power of calendar events.