Continuing with the Systemd tutorial, these special examples will show you how to make better use of the Systemd timer unit.

In this Systemd series of tutorials, we have discussed the Systemd timer unit to some extent. However, before we start talking about sockets, let’s look at three examples that show how to make the best use of these units.

Simple Cron-like behavior

I collect Debian PopCon data every week, and it would be nice to collect it at the same time every time so I can see download trends for certain applications. This is a typical example of something that can be done using a CRon task, but systemd timers can do the same:

[timer] OnCalendar= Thu *-*-* 05:32:07 Unit= popcon.service [Install] WantedBy= basic.targetCopy the code

The actual popcon.service performs a regular WGET task and is nothing special. What’s new here is the OnCalendar= directive. This command allows you to run a service at a specific time on a specific date. In this example, Thu means “run on Thursdays” and *-*-* means “the exact year, month, and date is irrelevant”, which translates to “run on Thursdays only, regardless of year, month, and day”.

In this way, you set the running time of the service. I chose to run around 5:30 a.m. in CENTRAL European Daylight Time, when the server is not very busy.

If your server is down and you just missed the weekly deadline, you can also use features like Anacron in the same timer.

[timer] Unit=popcon.service OnCalendar=Thu *-*-* 05:32:07 Persistent=true [Install] WantedBy=basic.targetCopy the code

When you set the Persistent= directive to true, it tells Systemd to run the service immediately after startup if the server is down when it should be running. This means that if the machine goes down early Thursday morning (for maintenance, say), popcon.service will execute as soon as it starts up again. After that, it will return to its regular 5:32 a.m. run time on Thursdays.

So far, so simple and straightforward.

Delay the

But let’s take it up a notch and “improve” the Systemd-based monitoring system. Remember, when you plug in the camera, the system starts taking pictures. Let’s say you don’t want it to take a picture of your face while you’re installing the camera. You want the camera service to start a minute or two later, so you have time to plug in the camera and walk out of the frame.

To do this, first you need to change the Udev rule to point it to a timer:

ACTION=="add", SUBSYSTEM=="video4linux", ATTRS{idVendor}=="03f0", 
ATTRS{idProduct}=="e207", TAG+="systemd", ENV{SYSTEMD_WANTS}="picchanged.timer", 
SYMLINK+="mywebcam", MODE="0666"Copy the code

The timer looks something like this:

# picchanged.timer [Unit] Description= One minute after the camera is connected, Start picchanged [Timer] OnActiveSec= 1 m Unit= picchanged. Path [Install] WantedBy= basic.targetCopy the code

After you access the camera, the Udev rule is triggered, which invokes the timer. The timer starts and waits a minute (OnActiveSec= 1m), then runs picchange.path, which monitors the main image for changes. Picchanged.path is also responsible for touching webcan. Service, which is actually used to take photos.

Start and stop the Minetest server at specific times each day

In the last example, we think you decided to use Systemd as the only dependency. Honestly, Systemd is almost taking over your life anyway. Why not embrace this inevitability?

You have a Minetest service for your kids. But you also want to pretend that you care about their education and upbringing, and make sure they do their homework and chores. So make sure Minetest is only available for a certain amount of time each night, like 5 to 7.

This is not quite the same as “start the service at a specific time”. It’s easy to write a timer to start service at 5pm… :

# minetest. Timer [Unit] Description= Run minetest. Service [timer] OnCalendar= *-*-* 17:00:00 Unit= every day at 5pm minetest.service [Install] WantedBy= basic.targetCopy the code

… Writing a corresponding timer to shut down the service at a specific moment, however, requires a greater dose of lateral thinking.

Let’s start with the obvious — setting timers:

Minetest. Service [timer] OnCalendar= *-*-* 19:05:00 Unit= stopminetest.service [Install] WantedBy= basic.targetCopy the code

The tricky part here is telling stopminetest. Service to — you know — stopminetest. We could not pass the minetest server PID from minetest. And there are no obvious commands in the Systemd unit vocabulary to stop or disable running services.

Our trick is to use the Systemd Conflicts= directive. It is similar to systemd’s Wants= command, except that it does the opposite. If you have a B.service unit that contains a Wants= A.service command, when the unit starts, b.service will run if A.service is not running. Similarly, if your B.service unit has a line that says Conflicts= A.service, Systemd will stop A.service when B.service starts.

This mechanism is used in situations where two services conflict when trying to control the same resource at the same time, such as when two services want to access a printer at the same time. By setting Conflicts= in the preferred service, you can ensure that it overrides the least important services.

However, you’ll use Conflicts=. In a slightly different scenario. You’ll use Conflicts= to cleanly close minetest. Service:

# stopMinetest. Service [Unit] Description= Close Minetest service Conflicts= Minetest. Service [service] Type= oneshot ExecStart=  /bin/echo "Closing down minetest.service"Copy the code

Stopminetest. Service doesn’t do anything special. In fact, it doesn’t do anything. But because it contains the Conflicts= line, Systemd turns minetest. Service off when it starts.

There’s one last ripple in your perfect Minetest setup: What if you leave work late, miss the server boot time, and the game isn’t over when you boot up? The Persistent= directive (as described above) can still run the service after missing the start time, but this scenario still doesn’t work. If you turn the server on at 11 a.m., it will start Minetest, which is not what you want. What you really need is a way to make sure Systemd only starts Minetest between 5 and 7 PM:

# minetest. Timer [Unit] Description= Run minetest. Service [timer] OnCalendar= *-*-* 17.. 19:*:00 Unit= minetest.service [Install] WantedBy= basic.targetCopy the code

OnCalendar= *-*-* 17.. 19:*:00 There are two interesting things about this line: (1) 17.. 19 is not a point in time, it’s a period of time, in this case 17 to 19; And, * in the (2) minute field indicates that the service runs every minute. So, you’ll read it as “Run minetest. Service every minute between 5pm and 7pm.”

There’s just one problem: Once minetest. Service is up and running, you’ll want Minetest. Timer not to try to run it again. You can include a Conflicts= directive in minetest. Service:

# minetest. Service [Unit] Description= Run minetest server Conflicts= Minetest. Timer [service] Type= simple User= <your User  name> ExecStart= /usr/bin/minetest --server ExecStop= /bin/kill -2 $MAINPID [Install] WantedBy= multi-user.targeCopy the code

The Conflicts= directive above ensures that minetest. Timer stops immediately after minstest. Service runs successfully.

Now, enable and start minetest. Timer:

systemctl enable minetest.timer
systemctl start minetest.timerCopy the code

Also, if you start the server at six o ‘clock, minetest. Timer is enabled; Between five and seven, Minetest. Timer tries to start minetest. Service every minute. However, once minetest. Service is running, Systemd will stop minetest. Timer because it will “conflict” with Minetest.

It’s counterintuitive to kill the timer that started a service when you first started it, but it works.

conclusion

You might think that there are better ways to do these things. I’ve seen the term “overdesign” in many articles, especially when systemd timers are used instead of Crons.

However, the purpose of this series of articles is not to provide the best solution to any specific problem. Its purpose is to use Systemd as much as possible to solve problems, even to the point of absurdity. Its purpose is to show a number of examples of how different types of units and the instructions they contain can be utilized. Our reader, you, will find practical examples of all this in this article.

However, we have one more thing to do: Next time, we’ll focus on Sockets and targets, and then we’ll finish our introduction to the Systemd unit.

You can learn more about Linux through free introductory Linux courses at the Linux Foundation and edX.


via: https://www.linux.com/blog/intro-to-linux/2018/8/systemd-timers-two-use-cases-0

By Paul Brown (Lujun9972

This article is originally compiled by LCTT and released in Linux China