3

Abstracted example:

I have two recurring tasks A and B that I want to setup as systemd services. As the tasks are quite similar to each other, I am using a template [email protected]; A and B will be running as instances of that template: [email protected] and [email protected], respectively.

# [email protected]
[Unit]
Description= myservice %I

[Service]
Type=oneshot
IOSchedulingClass=idle
ExecStart=bash -c "echo Starting %I; sleep 10; echo Finished %I"
Restart=on-failure

The recurring requirement of the two tasks should be handled via two timers, myservice-A.timer and myservice-B.timer. The timers will make sure that the two tasks are repeated according to configured time intervals, e.g. A on a weekly basis and B on a daily basis. The timers guarantee this even for the case that the PC was shut off at that time, in which case they will simply start the service as soon as possible when the pre-configured restart time has surpassed.

This last case however, can conflict with the requirement that A has to finish before B (if both are started simultaneously). As I am using template instances, I cannot use the Before= and After= options on the service itself. I can add them to the timers, but this does not seem to solve the problem (probably because now the timers just get an ordering dependency, but not the services they are starting).

# myservice-A.timer
[Unit]
# The Before= requirement below does not help
Before=myservice-B.timer
Description=weekly execution of myservice

[Timer]
OnCalendar=Monday *-*-* 09:20:00
Persistent=true
[email protected]

[Install]
WantedBy=timers.target
# myservice-B.timer
[Unit]
# the After= requirement below does not help
After=myservice-A.timer
Description=daily execution of myservice

[Timer]
OnCalendar=09:30:00
Persistent=true
[email protected]

[Install]
WantedBy=timers.target

Note that B does not require execution of A, i.e. I am not looking for a dependency of the type Requires=. I am only talking about the case that when both A and B are started via their timers, then A has to have finished before B is started.

1 Answer 1

4

As I am using template instances, I cannot user the Before= and After= options on the service itself.

You can, however, set these on particular instances of the template. However, for either relation to work well, note that:

Most importantly, for service units start-up is considered completed for the purpose of Before=/After= when all its configured start-up commands have been invoked and they either failed or reported start-up success.

That's to say, [email protected] means once the ExecStart command starts executing. It won't wait for it to finish. If, however, you do the actual work of these units in ExecStartPre commands, and maybe just use a simple /bin/true for ExecStart, then the ordering should work. Maybe like so:

# [email protected]
[Unit]
Description= myservice %I
[email protected]  # Will be skipped for `myservice@A` itself

[Service]
Type=oneshot
IOSchedulingClass=idle
ExecStartPre=/bin/bash -c "echo Starting %I; sleep 10; echo Finished %I"
ExecStart=/bin/true
Restart=on-failure

If your command takes a long time to execute, you might want to configure set TimeoutStartSec accordingly.

6
  • Thanks for the quick response! I was totally unaware of the possibility to include dependencies on instances in the template itself. Specifically I expected self-referencing, as exemplified by you with [email protected] to be an issue, but that turns out to not be the case! A question that remains for me is whether pushing the work into ExecStartPre might somehow interfere with the restarting nature of the service compared to a failure happening in ExecStart.
    – bluesheep
    Commented Mar 25 at 14:17
  • 1
    @bluesheep according to the spec for Restart=: "Configures whether the service shall be restarted when the service process exits, is killed, or a timeout is reached. The service process may be the main service process, but it may also be one of the processes specified with ExecStartPre=, ..."
    – muru
    Commented Mar 25 at 14:27
  • The last question left would be: What if there are three services A, B and C, with the (transitive) requirement: B starts only after A is finished, C starts only after B is finished? I cannot simply add [email protected] [email protected] to the template, as this would create a wrong dependency of A waiting for B. I am sorry I did not directly include this in my initial question, as I did not foresee that transitive ordering dependencies like these would complicate your solution.
    – bluesheep
    Commented Mar 25 at 14:35
  • @bluesheep then I'd say it's time to move on from templates and simply make three separate units
    – muru
    Commented Mar 25 at 14:37
  • 1
    Yes, templates are limited in that way, apparently by design: github.com/systemd/systemd/issues/14391 was closed, and see also this comment
    – muru
    Commented Mar 25 at 14:55

You must log in to answer this question.

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