1. Introduction

Sometimes, we need to restart systemd services to resolve operational errors. We can automate this using various methods in Linux. In this tutorial, we’ll look at three ways in which we can restart a systemd service periodically.

2. Using a Oneshot Service

Oneshot services are systemd services that perform a specific task and terminate upon completion of that task. In other words, the process is short-lived. We can periodically start a systemd service using a timer and a oneshot service.  We’ll use the timer service to trigger the oneshot service. Subsequently, the oneshot service will be responsible for restarting our systemd service. We create all systemd service unit files in the /etc/systemd/system directory. We create three systemd unit files called my-service.service, oneshot.service, and my-service.timer. Let’s define a service called my-service.service, which will perform a specific task:

$ sudo vi my-service.service 
[Unit]
Description=Simple service

[Service]
Type=simple
ExecStart=/usr/bin/logger hello

[Install]
WantedBy=multi-user.target

This service will make a simple entry into the system log. In our case, we are logging the message “hello“. Therefore, we should see the “hello” output in our logs once the service runs. Subsequently, let’s create the oneshot.service file:

$ sudo vi oneshot.service 
[Unit]
Description=One shot service

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart my-service.service

[Install]
WantedBy=multi-user.target

The oneshot.service file will restart my-service.service. Lastly, we set up the systemd timer:

$ sudo vi my-service.timer 
[Unit]
Description=Run oneshot service periodically

[Timer]
Unit=oneshot.service
OnCalendar=Mon..Fri 10:30

[Install]
WantedBy=timers.target

The oneshot.service file will be triggered by the systemd timer we’ve created. In this example, the systemd service my-service will restart at 10:30 a.m. on weekdays. Furthermore, we start the timer just as we’d start any other systemd service:

$ systemctl enable --now my-service.timer

We can see when the timer has run and when it is going to run by listing the systemd timers:

$ systemctl list-timers 
NEXT                          LEFT          LAST                          PASSED       UNIT                         ACTIVATES
Fri 2021-12-24 09:39:42 SAST  3min 13s left Fri 2021-12-24 08:36:22 SAST  1h 0min ago  dnf-makecache.timer          dnf-makecache.service
Fri 2021-12-24 10:30:00 SAST  53min left    Fri 2021-12-24 09:22:03 SAST  14min ago    my-service.timer             oneshot.service

After checking the system logs, we see that our service did run:

$ journalctl --since "5 minutes ago"
Dec 24 10:30:03 localhost.localdomain systemd[1]: Started Simple service.
Dec 24 10:30:03 localhost.localdomain systemd[1]: oneshot.service: Succeeded.
Dec 24 10:30:03 localhost.localdomain systemd[1]: Started One shot service.
Dec 24 10:30:03 localhost.localdomain root[4385]: hello
Dec 24 10:30:03 localhost.localdomain systemd[1]: my-service.service: Succeeded.

3. Using the RuntimeMaxSec and the Restart Options

Alternatively, we can use the RuntimeMaxSec option to terminate a systemd service after running for a certain amount of time. Also, we set the Restart descriptor to always. This option makes sure that the service is always restarted.  This method doesn’t work on oneshot services. This is because oneshot services always terminate upon the completion of a task. Thus, using the my-service.service unit file won’t work in this case. Let’s create a simple systemd service and name it my-service1.service:

$ sudo vi my-service1.service 
[Unit]
Description=Simple service

[Service]
ExecStart=/usr/bin/python3 /root/app.py
RuntimeMaxSec=180s
Restart=always

[Install]
WantedBy=multi-user.target

This service will execute a basic python program that runs indefinitely. Moreover, this service will terminate after 180 seconds and restart again:

Dec 24 18:50:57 localhost systemd[1]: Started Simple service.
Dec 24 18:53:57 localhost systemd[1]: my-service1.service: Service reached runtime time limit. Stopping.
Dec 24 18:53:57 localhost systemd[1]: my-service1.service: Failed with result 'timeout'.
Dec 24 18:53:57 localhost systemd[1]: my-service1.service: Service RestartSec=100ms expired, scheduling restart.
Dec 24 18:53:57 localhost systemd[1]: my-service1.service: Scheduled restart job, restart counter is at 1.
Dec 24 18:53:57 localhost systemd[1]: Stopped Simple service.
Dec 24 18:53:57 localhost systemd[1]: Started Simple service.

4. Using a Cronjob

Alternatively, we can specify the command we’d like to run in a crontab instead of a service file. Let’s edit our crontab:

$ crontab -e
30 10 * * 1-5 /usr/bin/systemctl restart my-service.service

Here, our entry specifies that we want to restart my-service.service at 10:30 a.m. every weekday. Furthermore, if the service is disabled, it’ll be started again.

5. Conclusion

In this article, we’ve explored different techniques that allow us to gracefully restart simple and oneshot systemd services.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.