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"
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.