3

I'm trying to create dependencies between two services described in systemd unit files:

  • a.service has to start before b.service
  • b.service can not start if a.service fails

Here is what I have:

% cat a.service
[Unit]
Description=A-Service
Before=b.service

[Service]
ExecStart=/opt/a.sh

[Install]
WantedBy=multi-user.target

% cat b.service
[Unit]
Description=B-Service
After=a.service

[Service]
ExecStart=/opt/b.sh

[Install]
WantedBy=multi-user.target

And this are simple scripts executed for service A and B:

% cat a.sh
#!/bin/sh
echo "A service started"
exit 0

% cat b.sh
#!/bin/sh
echo "B service started"
while [ true ]; do
   sleep 1
do
exit 0

So I've tried to emulate a/service failure by returning exit 1 from a.sh, systemctl status a.service reports it as failed:

Active: failed (Result: exit-code) ...
Process: 843 ExecStart=/opt/a.sh (code=exited, status=1/FAILURE)
...

However b.service still starts and active:

% systemctl status b.service
...
Active: active (running) ...
Process: 844 ExecStart=/opt/b.sh (code=exited, status=0/SUCCESS)
...

Moreover b.service dependencies do contain a.service (with status Fail):

% systemctl list-dependencies b.service
...

What am I doing wrong? Is it a problem with the scripts or [Unit] definition is not complete?

1 Answer 1

4

I would use a Requires attribute in the second unit:

If this unit gets activated, the units listed will be activated as well. If one of the other units fails to activate, and an ordering dependency After= on the failing unit is set, this unit will not be started.

I also changed the Type of each unit to be forking, since the default type of "simple" will consider the unit started once the shell has been started, while a forking unit will wait for the shell to exit. This Type change is critical here only for A-Service.

I also removed Before=b.service from A-Service, since a backwards dependency from B -to- A (with B's "After" directive) makes more sense to me, and you don't have to have both.

The resulting unit files are:

[Unit]
Description=A-Service

[Service]
Type=forking
ExecStart=/opt/a.sh

[Install]
WantedBy=multi-user.target

and:

[Unit]
Description=B-Service
Requires=a.service
After=a.service

[Service]
Type=forking
ExecStart=/opt/b.sh

[Install]
WantedBy=multi-user.target

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .