5

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?

7

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.

| improve this answer | |
  • 1
    Perfect! This is indeed a neat solution. Even with a good exit code ;) Thanks! – Wuff Mar 2 '19 at 8:20
  • 3
    Wow systemctl -q is-active doesn't work with Type=oneshot services. Well, but there is an easy work around, just need to change the first line to: if systemctl is-active A.service | grep activating; then. – Wuff Mar 2 '19 at 9:06
  • @Wuff Type=oneshot contradicts this method. It has a live-span of basically zero. – Suuuehgi Oct 20 at 14:34
  • 1
    Thank you for the work-around! It seems like a very useful directive to me -- say InhibitedBy. E.g. you have a .timer that should not run when specific .service-files are on-going. – Suuuehgi Oct 20 at 20:37
  • I found that simply using After= was sufficient for my use case. See unix.stackexchange.com/a/562959/22666 – Johann Oct 27 at 2:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.