~rumpelsepp/homepage

ref: 2a0829d7d5c82198e590e856efc864471be97a18 homepage/_posts/2014-11-15-cron-jobs-with-systemd-timer.adoc -rw-r--r-- 7.1 KiB
2a0829d7Stefan Tatschner add degoogle | A huge list of alternatives to Google products. Privacy tips, tricks, and links. 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# Cron Jobs with systemd.timer

[quote, https://wiki.archlinux.org/index.php/Systemd/Timers]
Timers are systemd unit files whose name ends in `.timer` that control
`.service` files or events. Timers have the ability to be an alternate to cron.
Timers have built-in support for calendar time events, monotonic time events,
and have the ability to run asynchronously.

There are lots of flamewars against systemd; mostly introduced by people who
grew up with e. g. sysvinit scripts. Besides these flamewars systemd provides a
very well documented and very easy to use out of the box solution for many tasks
of an administrator.

At first we have to clarify a few terms and definitions. Systemd grows from
release to release and it has a lot of different concepts we have to deal with.
The first concept I have to introduce for a cron replacement with systemd is
`systemd.service`.

## systemd.service

Service files are commonly used to start and stop programs. The `systemctl` tool
provides the necessary commands to control your services, such as start, stop,
restart, reload, and so on. It is your job (or the job of the package
maintainer) to write an appropriate service file so that `systemctl` is able to
map e.g. the start command to the corresponding shell command.

Let's do a simple example. Somebody has written an awesome backupscript and he
wants that program to be executed daily. The start command for that piece of
software might be something like:

----
$ awesome_program start
----

So we have to tell systemd that command first. Don't forget to put the *full
path* of your script into `ExecStart`. Otherwise systemd is not able to find
it!

[source, ini]
./etc/sytemd/system/awesome.service
----
[Unit]
Description=My awesome backup script
After=network.target

[Service]
Type=oneshot
ExecStart=/path/to/awesome_programm start
----

We call this file `awesome.service`. The structure of systemd service files is
self-explanatory. The `[Unit]` section is used to define some metadata such as
the description or dependencies. The `[Service]` section actually defines the
start command of our service. As we are most likely using a script which runs
and exists after finishing its tasks we have to set the Type to `oneshot`, see
also
http://www.freedesktop.org/software/systemd/man/systemd.service.html[systemd.service(5)].
Maybe I will give more information about that topic in another articles.

Now there is the question where we are supposed to put this file. This topic is
covered in detail in
http://www.freedesktop.org/software/systemd/man/systemd.unit.html[systemd.unit(5)].
At the moment we are just interested in the local configuration path when
running in system mode: `/etc/systemd/system`. So let's copy this service to
it's intended location `/etc/systemd/system/awesome.service`.

## systemd.timer

In the previous section we have covered the required steps to design a simple
systemd service which is used to start our script. Now we will add the unit
which is used to trigger the service. The timer has to be named according to the
corresponding service `awesome.timer`; we put this file in the same directory.

[source, ini]
./etc/sytemd/system/awesome.timer
----
[Unit]
Description=Weekly trigger for my awesome program

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=multi-user.target
----

The timer file is self-explanatory as well. It has three required sections:
`[Unit]`, `[Timer]` and `[Install]`.

I will now focus on the `[Timer]` section. It is used to define when the timer
should be activated. At first there is the `OnCalender` option. It understands a
few keywords such as `minutely`, `hourly`, `daily`, `monthly`, `weekly`,
`yearly`, `quarterly`, `semiannually`.  If these keywords fit into your
requirements everything is fine; more fine graned control is provided by
http://www.freedesktop.org/software/systemd/man/systemd.time.html[systemd.time(7)]. 
Maybe you want to run your service every six hours. So you
have to define the `OnCalendar` option like this:

----
OnCalendar=*-*-* 0/6:42:42
----

This means in detail (according to [systemd.time(7)][2]):

Run on

* every year (first asterisk),
* every month (second asterisk),
* every day (third asterisk)
* on 00:42:42 and repeat every 6 hours.

The repeating is defined with the slash. An OnCalender which runs every six
minutes instead would look like this:

----
OnCalendar=*-*-* 0:0/6:42
----

Just for the sake of completeness, `Persistent=true` means that any missed timer
will run after bootup. It is useful to catch up on missed runs of the service
when the machine was off. It is compareable to anacron.

Last but not least there is the Install section left. This one is needed for the
most important part: enabling the timer. We do this with `systemctl enable
awesome.timer`. Installing the timer into the multi-user.target just means we
want it to be started during bootup. If you want to dive into more detail check
out the https://wiki.archlinux.org/index.php/Systemd#Targets[Arch Wiki]. As we 
do not want to reboot now we also have to start the timer using

----
$ systemctl start awesome.timer
----

### Listing timers

Let's check if everything works as expected. Systemctl has a built in command to
list and inspect timers on your system.

----
$ systemctl list-timers
----

will tell you which timers have been recognized by systemd.

## Where is the user crontab?

Maybe you have wondered why you have to copy every file into system directories.
As mentioned before this is for systemd running in system mode. These services
and timers are started and enabled system wide for all users on the machine. If
you do not have sudo privileges or you just want to define your own timer you
can use systemd's user mode.

[quote, https://wiki.archlinux.org/index.php/Systemd/Timers]
https://wiki.archlinux.org/index.php/Systemd[systemd] offers users the ability
to manage services under the user's control with a per-user systemd instance,
enabling users to start, stop, enable, and disable their own units. This is
convenient for daemons and other services that are commonly run for a single
user, such as https://wiki.archlinux.org/index.php/Mpd[mpd] or to perform
automated tasks like fetching mail. With some caveats it is even possible to
run xorg and the entire window manager from user services.

You do not have to change that much for using systemd's user mode. Assuming you
are using a recent version of systemd the user instance is started automatically
per user session. You can use the `~/.config/systemd/user` directory for your
service and timer files. For enabling, starting and listing the timer you just
have to append `--user`, e. g.:

----
$ systemctl --user enable awesome.timer
----

### Using user mode on a server

As the systemd user instance is running per user session it might become
difficult to run certain tasks automatically without an open ssh session. If you
want systemd to run your user tasks *without being logged in* then just linger
yourself with:

----
$ loginctl enable-linger $USER
----

Lingering a specific user keeps the systemd user instance running without an
corresponding user session. This ensures that your tasks actually run as
intended.