The Type=oneshot
unit A.service
is started hourly by A.timer
and it Wants=B.service
, but runs Before=B.service
. Unit B.service
is also Type=oneshot
. The requirement here is that their processes should never overlap at run time (oneshot
ensures exactly that), all great so far. Now imagine a scenario where both A
and B
together run for more than an hour (time between A.timer
fires). There are two possibilities here:
A
runs more than an hour, then althoughA.timer
wants to fire and it probably does, regardless, another instance ofA
will not be started until the first one finishes as service instance uniqueness is one of fundamental principles insystemd
. I believe it will be merely queued. Again, all great so far, we have no risk of overlapping processes at run time here.A
runs long enough, so thatB
, which runs afterwards, also runs long enough to exceed one hour in total, and as a result,A.timer
fires to start newA
whileB
is still running. That's where we run into a process overlap because there is noAfter=B.service
inA.service
as there is alreadyBefore=B.service
.
My question is, basically, whether it is valid to even have both After=B.service
and Before=B.service
in A.service
in the first place? And, of course, would it resolve the overlapping issue described in the second possibility as I theoretically expect? Is there any other systemd
-way to solve this issue (e.g. I don't want to get involved with error-prone lock file bloat)?
If you create a
Before=
and anAfter=
in yourA.service
file, you will get an error:Because Systemd doesn't want to have both of those dependencies on the same unit. I don't think that any of the
Condition...=
fromman systemd.unit
that Michael mentioned are well-suited for the task that you are trying to accomplish, unless your commands do create and then clean up their own files. The way I see it, you have two main possible solutions:ExecCondition=
in yourA.service
that runs a command to check ifB.service
is running. This is a bit tricky to do with just ps and grep from within your unit file, so you'd probably want to execute some external script, but you already said you wanted to avoid a messy lockfile so that is probably not ideal.B.service
and into aExecStopPost=
option inA.service
. This will cause the second command to run only after the first command has stopped. It will also prevent a newA.service
from running before the first one completely finishes. I believe that this accomplishes all of your desires, since theA.service
command andB.service
command will never be run at the same time, twoA.service
commands will never be run alongside each other, and new executions will just be queued.Here is the unit file that I used to test option 3:
And then tested using
systemctl start A.service
repeatedly in multiple terminal windows, monitoring the progress of which processes were actually running at any given moment withps
.