0

Context

I want A.service to be started only after B.service finishes starting up, and B.service is a unit that's activated by the corresponding systemd path unit: B.path. Relevant code snippets can be found below.

A.service:

[Unit]
After=B.service

B.path:

[Path]
PathExists=/some/path

[Install]
RequiredBy=A.service

Problem

During bootup, I can see that A.service does activate B.path, and then B.service is activated after /some/path is there, but the problem is that A.service still starts before B.service finishes starting up. From checking the journald logs, the timeline looks like this:

  • T0:
    • A.service is started (and then failed coz its setup depends on B.service)
    • B.path is started
  • T0 + X seconds:
    • B.service is started

X is somewhere between 3~6 depending on when the path comes into existence during bootup.

Documentation

I checked the systemd documentation for Before=, After= (link) and found this:

If unit foo.service contains the setting Before=bar.service and both units are being started

This makes me wonder if it's because of the both units are being started bit. To be specific, B.service was only being started after /some/path is there, which can be X seconds after A.service was being started.

However, I'm not sure if my understanding of the documentation is correct, or I am actually missing something else. Either way, any recommendation to write the unit files to achieve what I want is appreciated. Thanks!

1
  • Why make B.path required by A.service then? Wouldn't it be much easier to want / require A.service with B.service? (And let whatever appropriate want / requires B.path, such as multi-user.target)
    – Tom Yan
    Commented Oct 19, 2023 at 10:37

1 Answer 1

0

A bit difficult to answer given that the actual unit files in question are omitted, but you seem to misunderstand what Before=/After= are meant to do;

The implication when using Before/After in unit files is that given a prioritization decision between two or more units, the Before/After conditions will determine the order in which actions are taken on the units.

In your case you have two services in which one service A.service is dependent on a second service B.service, however you have not specified that these two services have a dependency relationship, only the order in which they would execute if they had one.

With this being the case, it sounds like you want to also set Requisite=, Requires= or Wants= on A.service in reference to B.service such that A.Service looks as follows:

[Unit]
Requires=B.service
After=B.service

With this configuration, activation of the service A.service will necessitate activation of B.service and the After= directive will ensure that A.service will not begin execution of its ExecStart= directive(s) until after B.service has completed execution of its own ExecStart= directive(s)

Requires= and Wants= will not only check if listed units are already active, but will also activate them if they were not already

Requisite= will only check if a unit is running, if it is not, the unit it is defined in will immediately fail

Before= and After= only specify the order of activation for units when called simultaneously. Which is why you can have A.service activate before B.service in your current configuration, since they aren't currently being simultaneously activated, the ordering dependency is not applied.

It would be good coverage to also set Before=A.service on B.service

TLDR: You need to define both After= as well as Requires=. You "need" Requires= to ensure that if B.service is not already running, it will be activated at the same time as when A.service is ran. You need After= to specify that when A.service and B.service have a simultaneous activation, that A.service will delay its execution until after B.service has executed.

You must log in to answer this question.

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