07-24-2018, 03:50 PM
Setting Up a Timer with systemd in Linux
<div style="margin: 5px 5% 10px 5%;"><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/setting-up-a-timer-with-systemd-in-linux.jpg" width="1500" height="805" title="" alt="" /></div><div><div><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/setting-up-a-timer-with-systemd-in-linux.jpg" class="ff-og-image-inserted" /></div>
<p>Previously, we saw how to enable and disable systemd services <a href="https://www.linux.com/blog/learn/intro-to-linux/2018/5/writing-systemd-services-fun-and-profit">by hand</a>, <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">at boot time and on power down</a>, <a href="https://www.linux.com/blog/intro-to-linux/2018/6/systemd-services-reacting-change">when a certain device is activated</a>, and <a href="https://www.linux.com/blog/learn/intro-to-linux/2018/6/systemd-services-monitoring-files-and-directories">when something changes in the filesystem</a>.</p>
<p>Timers add yet another way of starting services, based on… well, time. Although similar to cron jobs, systemd timers are slightly more flexible. Let’s see how they work.</p>
<h3>“Run when”</h3>
<p>Let’s expand the <a href="https://www.minetest.net/">Minetest</a> <a href="https://www.linux.com/blog/learn/intro-to-linux/2018/5/writing-systemd-services-fun-and-profit">service you set up</a> in <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">the first two articles of this series</a> as our first example on how to use timer units. If you haven’t read those articles yet, you may want to go and give them a look now.</p>
<p>So you will “improve” your Minetest set up by creating a timer that will run the game’s server 1 minute after boot up has finished instead of right away. The reason for this could be that, as you want your service to do other stuff, like send emails to the players telling them the game is available, you will want to make sure other services (like the network) are fully up and running before doing anything fancy.</p>
<p>Jumping in at the deep end, your <i>minetest.timer</i> unit will look like this:</p>
<pre>
# minetest.timer
[Unit] Description=Runs the minetest.service 1 minute after boot up [Timer] OnBootSec=1 m Unit=minetest.service [Install] WantedBy=basic.target
</pre>
<p>Not hard at all.</p>
<p>As usual, you have a <code>[Unit]</code> section with a description of what the unit does. Nothing new there. The <code>[Timer]</code> section is new, but it is pretty self-explanatory: it contains information on when the service will be triggered and the service to trigger. In this case, the <code>OnBootSec</code> is the directive you need to tell systemd to run the service after boot has finished.</p>
<p>Other directives you could use are:</p>
<ul>
<li><code>OnActiveSec=</code>, which tells systemd how long to wait after the timer itself is activated before starting the service.</li>
<li><code>OnStartupSec=</code>, on the other hand, tells systemd how long to wait after systemd was started before starting the service.</li>
<li><code>OnUnitActiveSec=</code> tells systemd how long to wait after the service the timer is activating was last activated.</li>
<li><code>OnUnitInactiveSec=</code> tells systemd how long to wait after the service the timer is activating was last deactivated.</li>
</ul>
<p>Continuing down the <i>minetest.timer</i> unit, the <code>basic.target</code> is usually used as a synchronization point for late boot services. This means it makes <i>minetest.timer</i> wait until local mount points and swap devices are mounted, sockets, timers, path units and other basic initialization processes are running before letting <i>minetest.timer</i> start. As we explained in <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">the second article on systemd units</a>, <i>targets</i> are like the old run levels and can be used to put your machine into one state or another, or, like here, to tell your service to wait until a certain state has been reached.</p>
<p>The <i>minetest.service</i> you developed in the first two articles <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">ended up</a> looking like this:</p>
<pre>
# minetest.service
[Unit] Description= Minetest server Documentation= https://wiki.minetest.net/Main_Page [Service] Type= simple User= ExecStart= /usr/games/minetest --server
ExecStartPost= /home//bin/mtsendmail.sh "Ready to rumble?" "Minetest Starting up" TimeoutStopSec= 180 ExecStop= /home//bin/mtsendmail.sh "Off to bed. Nightie night!" "Minetest Stopping in 2 minutes" ExecStop= /bin/sleep 120 ExecStop= /bin/kill -2 $MAINPID [Install] WantedBy= multi-user.target
</pre>
<p>There’s nothing you need to change here. But you do have to change <i>mtsendmail.sh</i> (your email sending script) from this:</p>
<pre>
#!/bin/bash # mtsendmail
sleep 20 echo $1 | mutt -F /home/<<i>username</i>>/.muttrc -s "$2" my_minetest@mailing_list.com
sleep 10
</pre>
<p>to this:</p>
<pre>
#!/bin/bash
# mtsendmail.sh
echo $1 | mutt -F /home/paul/.muttrc -s "$2" [email protected]
</pre>
<p>What you are doing is stripping out those hacky pauses in the Bash script. Systemd does the waiting now.</p>
<h3>Making it work</h3>
<p>To make sure things work, disable <i>minetest.service</i>:</p>
<pre>
sudo systemctl disable minetest
</pre>
<p>so it doesn’t get started when the system starts; and, instead, enable <i>minetest.timer</i>:</p>
<pre>
sudo systemctl enable minetest.timer
</pre>
<p>Now you can reboot you server machine and, when you run <code>sudo journalctl -u minetest.*</code> you will see how, first the <i>minetest.timer</i> unit gets executed and then the <i>minetest.service</i> starts up after a minute… more or less.</p>
<h3>A Matter of Time</h3>
<p>A couple of clarifications about why the <i>minetest.timer</i> entry in the systemd’s Journal shows its start time as 09:08:33, while the <i>minetest.service</i> starts at 09:09:18, that is less than a minute later: First, remember we said that the <code>OnBootSec=</code> directive calculates when to start a service from when boot is complete. By the time <i>minetest.timer</i> comes along, boot has finished a few seconds ago.</p>
<p>The other thing is that systemd gives itself a margin of error (by default, 1 minute) to run stuff. This helps distribute the load when several resource-intensive processes are running at the same time: by giving itself a minute, systemd can wait for some processes to power down. This also means that <i>minetest.service</i> will start somewhere between the 1 minute and 2 minute mark after boot is completed, but when exactly within that range is anybody’s guess.</p>
<p>For the record, <a href="https://www.freedesktop.org/software/systemd/man/systemd.timer.html#AccuracySec=">you can change the margin of error with <code>AccuracySec=</code> directive</a>.</p>
<p>Another thing you can do is check when all the timers on your system are scheduled to run or the last time the ran:</p>
<pre>
systemctl list-timers --all
</pre>
<p>The final thing to take into consideration is the format you should use to express the periods of time. Systemd is very flexible in that respect: <code>2 h</code>, <code>2 hours</code> or <code>2hr</code> will all work to express a 2 hour delay. For seconds, you can use <code>seconds</code>, <code>second</code>, <code>sec</code>, and <code>s</code>, the same way as for minutes you can use <code>minutes</code>, <code>minute</code>, <code>min</code>, and <code>m</code>. You can see a full list of time units systemd understands by checking <code>man systemd.time</code>.</p>
<h3>Next Time</h3>
<p>You’ll see how to use calendar dates and times to run services at regular intervals and how to combine timers and device units to run services at defined point in time after you plug in some hardware.</p>
<p>See you then!</p>
<p><em>Learn more about Linux through the free <a href="https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux">“Introduction to Linux” </a>course from The Linux Foundation and edX.</em></p>
</div>
<div style="margin: 5px 5% 10px 5%;"><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/setting-up-a-timer-with-systemd-in-linux.jpg" width="1500" height="805" title="" alt="" /></div><div><div><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/setting-up-a-timer-with-systemd-in-linux.jpg" class="ff-og-image-inserted" /></div>
<p>Previously, we saw how to enable and disable systemd services <a href="https://www.linux.com/blog/learn/intro-to-linux/2018/5/writing-systemd-services-fun-and-profit">by hand</a>, <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">at boot time and on power down</a>, <a href="https://www.linux.com/blog/intro-to-linux/2018/6/systemd-services-reacting-change">when a certain device is activated</a>, and <a href="https://www.linux.com/blog/learn/intro-to-linux/2018/6/systemd-services-monitoring-files-and-directories">when something changes in the filesystem</a>.</p>
<p>Timers add yet another way of starting services, based on… well, time. Although similar to cron jobs, systemd timers are slightly more flexible. Let’s see how they work.</p>
<h3>“Run when”</h3>
<p>Let’s expand the <a href="https://www.minetest.net/">Minetest</a> <a href="https://www.linux.com/blog/learn/intro-to-linux/2018/5/writing-systemd-services-fun-and-profit">service you set up</a> in <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">the first two articles of this series</a> as our first example on how to use timer units. If you haven’t read those articles yet, you may want to go and give them a look now.</p>
<p>So you will “improve” your Minetest set up by creating a timer that will run the game’s server 1 minute after boot up has finished instead of right away. The reason for this could be that, as you want your service to do other stuff, like send emails to the players telling them the game is available, you will want to make sure other services (like the network) are fully up and running before doing anything fancy.</p>
<p>Jumping in at the deep end, your <i>minetest.timer</i> unit will look like this:</p>
<pre>
# minetest.timer
[Unit] Description=Runs the minetest.service 1 minute after boot up [Timer] OnBootSec=1 m Unit=minetest.service [Install] WantedBy=basic.target
</pre>
<p>Not hard at all.</p>
<p>As usual, you have a <code>[Unit]</code> section with a description of what the unit does. Nothing new there. The <code>[Timer]</code> section is new, but it is pretty self-explanatory: it contains information on when the service will be triggered and the service to trigger. In this case, the <code>OnBootSec</code> is the directive you need to tell systemd to run the service after boot has finished.</p>
<p>Other directives you could use are:</p>
<ul>
<li><code>OnActiveSec=</code>, which tells systemd how long to wait after the timer itself is activated before starting the service.</li>
<li><code>OnStartupSec=</code>, on the other hand, tells systemd how long to wait after systemd was started before starting the service.</li>
<li><code>OnUnitActiveSec=</code> tells systemd how long to wait after the service the timer is activating was last activated.</li>
<li><code>OnUnitInactiveSec=</code> tells systemd how long to wait after the service the timer is activating was last deactivated.</li>
</ul>
<p>Continuing down the <i>minetest.timer</i> unit, the <code>basic.target</code> is usually used as a synchronization point for late boot services. This means it makes <i>minetest.timer</i> wait until local mount points and swap devices are mounted, sockets, timers, path units and other basic initialization processes are running before letting <i>minetest.timer</i> start. As we explained in <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">the second article on systemd units</a>, <i>targets</i> are like the old run levels and can be used to put your machine into one state or another, or, like here, to tell your service to wait until a certain state has been reached.</p>
<p>The <i>minetest.service</i> you developed in the first two articles <a href="https://www.linux.com/blog/learn/2018/5/systemd-services-beyond-starting-and-stopping">ended up</a> looking like this:</p>
<pre>
# minetest.service
[Unit] Description= Minetest server Documentation= https://wiki.minetest.net/Main_Page [Service] Type= simple User= ExecStart= /usr/games/minetest --server
ExecStartPost= /home//bin/mtsendmail.sh "Ready to rumble?" "Minetest Starting up" TimeoutStopSec= 180 ExecStop= /home//bin/mtsendmail.sh "Off to bed. Nightie night!" "Minetest Stopping in 2 minutes" ExecStop= /bin/sleep 120 ExecStop= /bin/kill -2 $MAINPID [Install] WantedBy= multi-user.target
</pre>
<p>There’s nothing you need to change here. But you do have to change <i>mtsendmail.sh</i> (your email sending script) from this:</p>
<pre>
#!/bin/bash # mtsendmail
sleep 20 echo $1 | mutt -F /home/<<i>username</i>>/.muttrc -s "$2" my_minetest@mailing_list.com
sleep 10
</pre>
<p>to this:</p>
<pre>
#!/bin/bash
# mtsendmail.sh
echo $1 | mutt -F /home/paul/.muttrc -s "$2" [email protected]
</pre>
<p>What you are doing is stripping out those hacky pauses in the Bash script. Systemd does the waiting now.</p>
<h3>Making it work</h3>
<p>To make sure things work, disable <i>minetest.service</i>:</p>
<pre>
sudo systemctl disable minetest
</pre>
<p>so it doesn’t get started when the system starts; and, instead, enable <i>minetest.timer</i>:</p>
<pre>
sudo systemctl enable minetest.timer
</pre>
<p>Now you can reboot you server machine and, when you run <code>sudo journalctl -u minetest.*</code> you will see how, first the <i>minetest.timer</i> unit gets executed and then the <i>minetest.service</i> starts up after a minute… more or less.</p>
<h3>A Matter of Time</h3>
<p>A couple of clarifications about why the <i>minetest.timer</i> entry in the systemd’s Journal shows its start time as 09:08:33, while the <i>minetest.service</i> starts at 09:09:18, that is less than a minute later: First, remember we said that the <code>OnBootSec=</code> directive calculates when to start a service from when boot is complete. By the time <i>minetest.timer</i> comes along, boot has finished a few seconds ago.</p>
<p>The other thing is that systemd gives itself a margin of error (by default, 1 minute) to run stuff. This helps distribute the load when several resource-intensive processes are running at the same time: by giving itself a minute, systemd can wait for some processes to power down. This also means that <i>minetest.service</i> will start somewhere between the 1 minute and 2 minute mark after boot is completed, but when exactly within that range is anybody’s guess.</p>
<p>For the record, <a href="https://www.freedesktop.org/software/systemd/man/systemd.timer.html#AccuracySec=">you can change the margin of error with <code>AccuracySec=</code> directive</a>.</p>
<p>Another thing you can do is check when all the timers on your system are scheduled to run or the last time the ran:</p>
<pre>
systemctl list-timers --all
</pre>
<p>The final thing to take into consideration is the format you should use to express the periods of time. Systemd is very flexible in that respect: <code>2 h</code>, <code>2 hours</code> or <code>2hr</code> will all work to express a 2 hour delay. For seconds, you can use <code>seconds</code>, <code>second</code>, <code>sec</code>, and <code>s</code>, the same way as for minutes you can use <code>minutes</code>, <code>minute</code>, <code>min</code>, and <code>m</code>. You can see a full list of time units systemd understands by checking <code>man systemd.time</code>.</p>
<h3>Next Time</h3>
<p>You’ll see how to use calendar dates and times to run services at regular intervals and how to combine timers and device units to run services at defined point in time after you plug in some hardware.</p>
<p>See you then!</p>
<p><em>Learn more about Linux through the free <a href="https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux">“Introduction to Linux” </a>course from The Linux Foundation and edX.</em></p>
</div>