Systemd Timer

This tutorial with show you how to replace your cron jobs with systemd timer.

Step 1 - Create your shell/bash script

I suspect that if you want to do a cron job you want to run something at a specific time. I will also suppose that you know how to create your shell script, so let's get to the meat of the subject right away.

Step 2 - Create a service

To create a service that can be recognized by systemd, you need to add the .service extension at the end of the file's name. You also need to but the service in the /etc/systemd/system/ folder.

The following will show you how to create a service.

[Unit]
Description=Write something that will allow you to remember what your service does.

[Service]
Type=oneshot
ExecStart=/path/to/your/shell/script/file
User=root
Group=systemd-journal

Alright, now use systemctl start your.service and systemctl enable your.service to activate your service.

Step 3 - Create a timer

In this step we will create a timer that will tell systemd when to run the service created during step 2.

Like the service, save it in the /etc/systemd/system/ folder. This time you need to your the .timer extension.

There are two kinds of timer.

Monotonic Timer

Big word to say that it will execute N minutes after boot and then at a specific interval

[Unit]
Description=A description that describes what the timer does.

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min

[Install]
WantedBy=your_file_name.service

Realtime timer

This is a cron style timer

In the following example, the script will run once a week on Monday at 12:00am. When Percistent=true is present, it triggers the script immediatly after boot if it missed the last execution.

[Unit]
Description=A description that describes what the timer does.

[Timer]
OnCalendar=weekly
Persistent=true

[Install]
WantedBy=your_file_name.service

To be more specific on your date and time, OnCalendar uses the following format.

DayOfWeek Year-Month-Day Hour:Minute:Second

An asterisk (*) can be use to specify any value in a specific field and commas (,) can be use to specify multiple values. Two values separated with two period (..) creates a range. Here's an example.

OnCalendar=Mon,Tue *-*-01..04 14:32:00

(Optional) Step 4 - Send an email if the script fails

If you desire, you can receive an email when something didn't go as plained. To do so, you will need a shell script that will send an email. Then you'll need a service to send that email.

Mail script example

Create your run script. For example /usr/local/bin/systemd-email

#!/bin/bash
/usr/bin/sendmail -t << ERRMAIL
To: $1
From: systemd 
Subject: $2
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset=UTF-8

$(systemctl status --full "$2")
ERRMAIL

Mail service

Now it's time to create the service. It looks almost like the previous service we created.

Save your script in the following location /etc/systemd/system/status-email-user@.service

[Unit]
Description: Status email for %i to 

[Service]
Type=oneshot
ExecStart=/usr/local/bin/system-email  %i
User=nobody
Group=systemctl-journal

Simply replace email address with the desired email adress

Final step

The only thing you need to do now is to add one line the service file(s) (controled by a timer file) you want to receive an email.

Put the following line under the [Unit] section.

OnFailure=status-email-user@%n.service

Management

The following let's you view all the running timers.

systemctl list-timers

Here is an output example.

NEXT                         LEFT                LAST                         PASSED             UNIT                         ACTIVATES
Mon 2018-02-19 10:19:54 AST  44min left          Sun 2018-02-18 10:19:54 AST  23h ago            systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Tue 2018-02-20 00:02:17 AST  14h left            Mon 2018-02-19 00:01:54 AST  9h ago             updatedb.timer               updatedb.service
Tue 2018-02-20 00:02:34 AST  14h left            Mon 2018-02-19 00:04:25 AST  9h ago             logrotate.timer              logrotate.service
Tue 2018-02-20 00:02:57 AST  14h left            Mon 2018-02-19 00:05:04 AST  9h ago             shadow.timer                 shadow.service
Tue 2018-02-20 00:03:30 AST  14h left            Mon 2018-02-19 00:03:04 AST  9h ago             man-db.timer                 man-db.service
Thu 2018-03-01 00:00:00 AST  1 weeks 2 days left Sat 2018-02-10 09:04:36 AST  1 weeks 2 days ago pamac-cleancache.timer       pamac-cleancache.service

Sources