systemd: Stop dependent service when main service crashes - linux

(systemd version 229)
I have a primary service A, and a secondary service B. The primary A can run by itself. But service B cannot run correctly by itself: it needs A to be running (technically B can run, but this is what I want systemd to prevent). My goal: If A is not running, B should not run. Given that A and B are running, when A stops or dies/crashes, then B should be stopped.
How do I achieve this?
I get close by adding [Unit] items to b.service, using
Requisite=A.service
After=A.service
The result of the above is that
B won't start unless A is running (good).
B is stopped when A is stopped (good).
However, if I kill A, service B continues to run (bad).
How can I fix this last behavior? Neither PartOf nor BindsTo seems to do the trick, but perhaps I don't have the right incantation of combinations of options? Its not clear to me from the man pages what options can be combined.
systemd.unit man page: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
Related: Systemctl dependency failure, stop dependent services

You can use, Requires= or PartOf= or BindTo=
see this article for detail of their usage

To achieve your 3rd objective make use of PartOf keyword.
In B.service you need to add dependency on A under [Unit] section as below
[Unit]
..
..
PartOf=A.service
With this, whenever A is killed B shall also stop.

If you start Service A with Type=notify you may be able to achieve something if you terminate A with SIGINT or SIGTERM, you can actually handle that and send a message on $NOTIFY_FD to systemd, but that option is still not possible with SIGKILL. It's a bit involved but might be able to achieve what you want.
You should also consider making A Restart=always. This will at-least make sure that A will remain available and B won't keep giving out errors. When you kill A (outside systemd), there's no way for systemd to know that A was killed - especially if you do so with kill -9 (SIGKILL cannot be handled). . So one of the best way to handle that will be to make Service A, Restart=always.

Related

Programing Rust to stop safety with systemctl

I'm writing a very demanding program in rust that had variable Threads for processing very important data, and want to know if there is a way that i can send a signal to stop it with systemctl in a way that i can be sure that it is finishing it's dutties before stop, as its very demanding, uses http_request, and threads are variables I can not make an estimation of how much time i have to wait since signal sended until the process is dead.
In esscense, it is a daemon that is in a loop until a variable sets false, like this
loop {
// Process goes here
if !is_alive {
break;
}
}
What i'm doing right now is that the program is asking a "config.json" file if it is "alive", but i think it's not the best way because i don't know when the program stops, just can see that is stoping, but not how much is going to last, and if i do this way, systemctl is going to show the service alive, even if i shuted it down manually.
If you want to experiment with Systemd service behavior, I would take a look at the Systemd documentation. In this case, I would direct you to the section about TimeoutStopSec.
According to the documentation, you can disable any timeout on systemd stop commands with TimeoutStopSec=infinity. This combined with actually handling the SIGTERM signal that systemd uses by default should do the trick.
Furthermore, there is the KillSignal option by which you can specify the signal that is sent to your program to stop it or ExecStop to specify a program to run in order to stop your service.
With these you should be able to figure it out, I hope.

Will systemd block system startup if daemon does not fork?

If I configure a systemd service in a way that type is set to "forking" and TimeoutStartSec is set to "infinity" then would my system startup block if the service configured never goes into background?
If not, what are the side effects of having such a configuration?
The systemd implementation was to replace the SYS-V which already was getting a parallel startup by specifying dependencies instead of a simple priority (order defined by a two digit number such as 05-service and 67-daemon). But the SYS-V was not constrained in any way, so most processes would not really be properly defined. (The priority system was a filename and the dependencies were defined in a comment at the start of your init script).
systemd drew heavily from that concept of starting things in parallel by implementing a make like mechanism where you can say to build B only once A is built.
# Makefile
B: A
generate-B
A: A.c
gcc -o A A.c
So systemd in general won't be blocked because of one rogue service, however, if you now create a second service (i.e. B in my make example) which depends on that service which never returns as expected, that second service will never be started. i.e.
# Makefile
B: A
generate-B [never reach since A never ends]
A: A.c
sleep forever
In other words, since your OS doesn't depend on your service, it will still load as expected. Your environment, however, is going to be affected if you start creating dependencies on your first services. On the other hand, there are probably various types of failsafe to circumvent, at least partially, the kind of setup you are talking about.

How can I run a service when the runlevel changes

I want to automatically start the proftpd service when the runlevel changes from 2 to 5. When it changes back to 2 it should be stopped again.
Any ideas?
If you use sysvinit, the procedure is easy. Just have a K??yourServiceName script in /etc/rc2.d and a S??yourServiceName in /etc/rc5.d. They will be called with the runlevel in $RUNLEVEL environment variable and with a stop and start (respectively) parameters. The ?? represent two digits that represent the order of execution to use (priority?).
This has been replaced in new scripts (mainly in debian, but I think others follow this approach also) by having several fields in the scripts themselves indicating the dependencies between scripts and execution is done in parallel for scriptis that don't depend on each other, but serially for scripts that depend between themselves. You can read about this approach in the scripts themselves. The scripts are installed normally in /etc/init.d, and symbolic links are made from there to the proper directory with the proper two digit positions by the utilities controlling this.
Finally, if you use systemd (it has replaced completely the sysv init process) there's another method to deal with it. You'll have to look for the doc of systemd(8) ad I'm not aware of it. I only know it's a dbus service provider and processes comunicate with it via this new technology.
The two first methods are somewhat interoperable, as if you fix the priority of execution and don't fill the dependencies, the system v init process will respect it.
Edit
This approach assumes you run proftpd as an independent service (not as dependant of xinetd(8) or inetd(8)) and it has scripts to launch and stop it on a runlevel change.
In case you need to run it depending on xinetd(8), i don't know now if xinetd has parameters to allow you to serve based on the runlevel. If it has, you are lucky. If it hasn't you will have to switch your approach.

Linux : Start a a service after a particular service has started on boot

I have two services A and B which I want to start on boot. But A should start first and then only B should start.
I enabled the services using systemctl enable service_name.
Now the services are starting but not in order i.e B is starting before A. Is there any way I can configure their start order?
You can add the following command at the end of the startup script of A, and disable B to be started on bootup: systemctl start B
They're starting out of order because Linux uses "makefile style concurrent boot" during startup -- and the A process is taking longer to start than the B process. The simplest way to delay process B is with a sleep command -- a few seconds is likely enough -- though this will delay the completion of startup by a fixed amount (and, if process A takes a variable time to start, as with opening a wifi connection etc., this may not always work unless you set the time higher than it usually needs to be).
More reliable, and possibly less delay in startup, would be to use something like lsproc | grep proc_a | wc -l to check for existence of process A (or a child of A) as a condition for starting process B -- put this in a short loop with a 1 or 2 second sleep (so it doesn't hog all your CPU while it waits) and it'll effectively keep B back until A is running, without unnecessary delay.

Linux job scheduler launching a script 2 hours after it terminates

I have a script that runs unknown period of time that depends on its input. It can run one hour when little data available, or it can run for 8 hours if much data is to be processed.
I need to run it periodically, particularly 2 hours after previous run was completed.
Is there an utility to do that?
Use 'at' instead of 'cron' and at the end of your script add:
at now +2 hours $*
This means that each occurrence is chained - so if it terminates abnormally the next instance won't be scheduled - but I don't think there's a more robust solution without adding a lot of code/complexity.
I don't like the at solution proposed, so here another solution:
Use cron to launch your every two hours
Upon startup, your application(*) checks if there's a pidfile.
2.1 if it is present, then there may be another instance running: read contents of the file (pid) and see if that pid is the pid of an existing process, a zombie process or something else. If it is the pid of a running, existing process, then exit. If it is the pid of a zombie process then the previous job ended unexpectedly and then you have to delete the pidfile and go to step 3. Otherwise.
After deleting pidfile, you create a new one and put your pid into it. Then proceed to do your job.
*: In order not to add complexity, this application i cited could also be a simple wrapper that spawns your code using exec.
This solution can also be scripted quite easily.
Hope it helps,
SnoopyBBT
If it looks complicated, here is another, dirtier solution:
while true ; do
./your_application
sleep 7200
done
Hope this helps,
SnoopyBBT

Resources