Linux – systemd: service dependency “If A is not running, B should not run”

linuxsystemd

(systemd version 229, fwiw)

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

1) B won't start unless A is running (good).
2) B is stopped when A is stopped (good).
3) However, if I kill A, service B continues to run (bad).

How can I fix this last behavior #3? I tried using BindsTo instead of Requisite, like this in B's service file:

BindsTo=A.service
After=A.service

and I get:

1) If A is not running and I start B, then A is also started
    (I want an error, I don't want A started)
2) B is stopped when A is stopped (good).
3) B is stopped when A is killed (good)

So now #3 is good but #1 is not the desired behaviour.
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.

With BindsTo, I also tried failing B's start using ExecStartPre, but of course this didn't work because the start of B had already determined that it needed A to run (and started it), before it fired up B.

Is there some way to get a behaviour inbetween Requisite and BindsTo? The 1-2-3 I've listed above?

Thanx in advance!

Best Answer

I'm also looking for a more elegant solution. There is an open systemd ticket for Request for enhancement here: https://github.com/systemd/systemd/issues/5966

Currently my workaround is as follow: B.service

Requisite=A.service
After=A.service

A.service

OnFailure=Stop-B.service

Stop-B.service

[Service]
Type=oneshot
TimeoutSec=0
ExecStart=/bin/systemctl stop B.service
Related Topic