How to set a conflict in systemd in one direction only

systemd

I have two systemd services A (takes a few minutes) and B (only very few seconds):

  • A has a high priority and must run under all circumstances.
  • B cannot be started when A runs, but there is no problem to start A when B still runs. It is even desired to start A even when B still runs, as A must run under all circumstances.
  • B shouldn't be killed when Conflicts= stops the service, instead it should still finish running.

The systemd man tells me:

Configures negative requirement dependencies. If a unit has a Conflicts= setting on another unit, starting the former will stop the latter and vice versa.

I thought using Conflicts=A.service might be the solution. The man tells me that starting A will stop B, but also what I don't want is B will stop A.

Is there a way to have Conflicts= just unidirectional?

Best Answer

The Conflict= directive is not really what you want, not only because it works in both directions, but also because you don't want to stop the currently running B.service (if one is running) when A.service starts.

The way I'd recommend you implement this is by adding an additional script to B.service that would check whether A.service is running and then prevent B.service from starting in that case.

You can do that by adding an ExecStartPre= to B.service that exits with a non-zero status, which will prevent it from going further in its startup.

My suggestion would be to add something like this to your existing /etc/systemd/system/B.service:

ExecStartPre=/bin/sh -c 'if systemctl -q is-active A.service; then \
                             echo "A.service already running, will not start B.service"; \
                             exit 75; \
                         fi'

This uses systemctl is-active to check whether service A.service is currently running.

If it doesn't, it echoes a message (which will end up in the journal and, more importantly, shown whenver you check systemctl status B.service.) Additionally, it will exit with a non-zero status. I picked exit code 75 since systemd will show that as EX_TEMPFAIL which means "Temporary failure; user is invited to retry." See here for how systemd interprets/names process exit codes.

Line wrapping is optional too, you can simply write everyting in a single line, just omitting the trailing \ used to wrap them.

Related Question