bella.network Blog

Services and timer using systemd

Manage startup of your programs using systemd on boot or using timers
Systemd manages tasks and services on Linux systems
Systemd manages tasks and services on Linux systems (Image from Pixabay)

Some Linux based systems like Debian and Ubuntu are using systemd as init daemon. That means that initially after loading the kernel, systemd is the first program which is started on the system which in result starts all other components of the system. Such service can be compared with Windows Services, where a service can be defined to run at start, run at specified intervals and use a specific user when executed.

Systemd provides many ways how a service can be configured. I am addressing the most basic ones which are most used in my day-to-day work with Linux systems. Such services enable tasks to be executed at system startup and on a time-controlled basis. At the same time, each execution is logged, allowing the output of the program to be viewed at a later date. In the event of malfunctions such as program crashes or unsuccessful execution, tasks can be re-executed as often as required or stopped after the 5th restart until an administrator checks the malfunction.

Service File

A service usually contains 3 main parts named Unit, Service and Install and is mostly stored in /usr/lib/systemd/system/, /etc/systemd/system/ or /lib/systemd/system/. The file extension is .service - for example /usr/lib/systemd/system/myservice.service.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Unit]
Description=A short service description what this service does
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myservice
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target

The service is divided into three parts: Unit, Service and Install.

Unit contains a main description of the service and contains dependencies to other services. Like the example above, After=network.target describes that the service should be started after the network management stack was started. This does not mean that an internet connection is currently active. It’s more important here that the service is stopped on shutdown before disconnecting network. This allows the application to close all open connections properly. If you want to add additional dependencies, these can be added with space as separator. For example only start the service after MySQL/MariaDB because the application requires a database connection: After=network.target mysql.service. The directives Before= and After= are only for ordering startup/shutdown of the service. If network isn’t available, the service will be started regardless.

Service contains the configuration how the service is started. Most important here is ExecStart= which describes which binary is started by the service. Type=simple is the most common type of service. It’s used for services which are started and stopped by systemd. If the service is a daemon which runs in the background, Type=forking is the right choice. Type=oneshot is used for services which are started and stopped immediately after the execution of the binary. Type=notify is used for services which send a notification to systemd when the service is ready to accept connections. This is mostly used for services which are started and stopped by systemd.

Restart=always describes that the service should be restarted if it crashes. RestartSec=10s describes that the service should be restarted after 10 seconds if it crashes. This is useful to prevent a service from crashing and restarting in a loop.

User= and Group= can be used to specify which user and group the service should run as. This is useful to run the service as a non-root user.

WorkingDirectory= can be used to specify the working directory of the service. This is useful if the service requires a specific directory to work properly.

EnvironmentFile= can be used to specify a file which contains environment variables. This is useful if the service requires environment variables to work properly.

Install describes where the service is installed when it get’s enabled. multi-user.target is mostly the right choice here. This means that the service is started when the system is in multi-user mode. This is the default mode of a Linux system.

An extended documentation is available at https://www.freedesktop.org/software/systemd/man/systemd.service.html.

Install and start service

After creating the service file, the service can be enabled and started using the following commands:

1
systemctl enable --now myservice

This command enables the service to start at boot and starts the service immediately.

Service state

The state of the service can be checked using the following command:

1
systemctl status myservice

This command shows the current state of the service, the last log entries and the current process ID of the service.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
systemctl status myservice.service

 myservice.service - A short service description what this service does
     Loaded: loaded (/usr/lib/systemd/system/myservice.service; enabled; preset: enabled)
     Active: active (running) since Sat 2024-07-20 20:26:54 UTC; 13h ago
   Main PID: 413056 (myservice)
      Tasks: 17 (limit: 19104)
     Memory: 24.3M (peak: 36.0M)
        CPU: 13min 17.867s
     CGroup: /system.slice/myservice.service
             └─413056 /usr/local/bin/myservice

Jul 21 10:22:42 brill myservice[413056]: Failure on HTTP request, teapot not found
Jul 21 10:22:48 brill myservice[413056]: Served tea to user
Jul 21 10:22:49 brill myservice[413056]: Detected loud noise in the room

If more information is required, the log entries can be viewed using the following command:

1
journalctl -u myservice

Additionally, most logs are written to the syslog which is most commonly located at /var/log/syslog.

Systemd Timer

A systemd timer can be used as modern replacement for cronjobs. It’s more flexible and provides more options to configure the execution of a task. A timer is always linked to a service which is executed by the timer.

As timers most commonly are used to execute a service at a specific time, the service should be of type oneshot. This means that the service is executed once and then stopped. If the service is of type simple, the service will be executed and systemd will wait for the service to finish. This is not the desired behavior for a timer.

We assume that the previously created service myservice is used in the following example and the type of the service is oneshot. The service should be executed every 5 minutes.

Timer File

A timer usually contains 3 main parts named Unit, Timer and Install and is mostly stored in /usr/lib/systemd/system/, /etc/systemd/system/ or /lib/systemd/system/. The file extension is .timer - for example /usr/lib/systemd/system/myservice.timer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Unit]
Description=A short timer description what this timer does
Requires=myservice.service

[Timer]
Unit=myservice.service
OnCalendar=*-*-* *:0/5:00
AccuracySec=1us

[Install]
WantedBy=timers.target

The main difference to a service file is that the timer contains a Timer section instead of a Service section. The Unit section is the same as in a service file.

Timer contains the configuration how the timer is executed. Most important here is OnCalendar=*-*-* *:0/5:00 which describes that the service should be executed every 5 minutes. The format of the OnCalendar directive is YYYY-MM-DD HH:MM:SS where * is a wildcard. The AccuracySec directive can be used to specify the accuracy of the timer. This is useful if the timer should be executed at a specific time.

Timer state

The state of the timer can be checked using the following command:

1
systemctl status myservice.timer

This command shows the current state of the timer, the last log entries and the current process ID of the timer.

1
2
3
4
5
6
7
 myservice.timer - A short timer description what this timer does
     Loaded: loaded (/usr/lib/systemd/system/myservice.timer; enabled; preset: enabled)
     Active: active (waiting) since Sun 2024-07-14 18:35:06 UTC; 6 days ago
    Trigger: Sun 2024-07-21 12:23:29 UTC; 1h 40min left
   Triggers:  myservice.service

Jul 14 18:35:06 brill systemd[1]: Started myservice.timer - A short timer description what this timer does

A detailed list of all timers can be viewed using the following command:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
systemctl list-timers

NEXT                            LEFT LAST                              PASSED UNIT                           ACTIVATES
Sun 2024-07-21 10:45:00 UTC      15s Sun 2024-07-21 10:40:00 UTC     4min ago myservice.timer                myservice.service
Sun 2024-07-21 10:45:20 UTC      35s Sun 2024-07-21 09:48:36 UTC    58min ago fwupd-refresh.timer            fwupd-refresh.service
Sun 2024-07-21 10:50:00 UTC 3min 15s Sun 2024-07-21 10:40:00 UTC     6min ago sysstat-collect.timer          sysstat-collect.service
Sun 2024-07-21 11:09:00 UTC    22min Sun 2024-07-21 10:39:00 UTC     7min ago phpsessionclean.timer          phpsessionclean.service
Sun 2024-07-21 12:23:29 UTC 1h 36min Sun 2024-07-21 06:50:48 UTC 3h 55min ago motd-news.timer                motd-news.service
Sun 2024-07-21 13:21:58 UTC 2h 35min Sun 2024-07-21 06:29:38 UTC 4h 17min ago ua-timer.timer                 ua-timer.service
Sun 2024-07-21 16:41:24 UTC 5h 54min Sun 2024-07-21 03:06:01 UTC       7h ago apt-daily.timer                apt-daily.service
Sun 2024-07-21 18:40:14 UTC       7h Sat 2024-07-20 18:40:14 UTC      16h ago update-notifier-download.timer update-notifier-download.service
Sun 2024-07-21 18:50:06 UTC       8h Sat 2024-07-20 18:50:06 UTC      15h ago systemd-tmpfiles-clean.timer   systemd-tmpfiles-clean.service
Mon 2024-07-22 00:00:00 UTC      13h Sun 2024-07-21 00:00:06 UTC      10h ago dpkg-db-backup.timer           dpkg-db-backup.service
Mon 2024-07-22 00:00:00 UTC      13h Sun 2024-07-21 00:00:06 UTC      10h ago logrotate.timer                logrotate.service
Mon 2024-07-22 00:07:00 UTC      13h Sun 2024-07-21 00:07:06 UTC      10h ago sysstat-summary.timer          sysstat-summary.service
Mon 2024-07-22 00:09:50 UTC      13h Mon 2024-07-15 00:56:15 UTC   6 days ago fstrim.timer                   fstrim.service
Mon 2024-07-22 04:56:20 UTC      18h Sun 2024-07-21 08:12:59 UTC 2h 33min ago man-db.timer                   man-db.service
Mon 2024-07-22 06:34:26 UTC      19h Sun 2024-07-21 06:06:21 UTC 4h 40min ago apt-daily-upgrade.timer        apt-daily-upgrade.service
Sat 2024-07-27 19:22:05 UTC   6 days Tue 2024-07-16 06:33:20 UTC   5 days ago update-notifier-motd.timer     update-notifier-motd.service
Sun 2024-07-28 03:10:07 UTC   6 days Sun 2024-07-21 03:10:17 UTC       7h ago e2scrub_all.timer              e2scrub_all.service

17 timers listed.
Pass --all to see loaded but inactive timers, too.

A systemd timer can be enabled, started and disabled the same way as a service:

1
systemctl enable --now myservice.timer

Conclusion

Systemd is a powerful tool to manage services and timers on Linux systems. It provides a lot of options to configure services and timers. This article only covers the most basic options. For more advanced options, the official documentation is recommended.