7.1 Relationships
Four relationship types. Each says something different about how two services interact at start, at stop, and on failure.
7.1.1 Requires #
A hard dependency. If A Requires B:
- Start. B has to reach a dependent-satisfying state before A
starts.
If B is not running, peinit starts it with cause
DependencyStart. If B enters Failed, A goes to Failed with causeDependencyFailurewithout attempting to start. - Stop. Stopping B does not stop A. This is a start-ordering constraint, not a runtime coupling.
- Runtime failure. If B crashes while A is Active, A is unaffected and keeps running. B's own restart policy handles B.
- Missing target. A goes to Failed with
DependencyFailure, detected at graph validation.
7.1.2 Wants #
A soft dependency. If A Wants B, peinit starts B before A — with
cause DependencyStart — provided B exists and is not disabled. If B
fails to start, or does not exist at all, A starts anyway. There is no
stop or failure effect in either direction.
The waiting rule is where the difference from Requires actually lives:
a dependent blocked on a Requires target waits for it to reach a
satisfying state, while a dependent blocked on a Wants target waits
only for it to reach any terminal state, satisfying or not. That is
what makes Wants ordering rather than dependency — "start this first
if you can, but I will work without it".
7.1.3 BindsTo #
A runtime coupling. If A BindsTo B:
- Start. Identical to
Requires. - Stop. If B stops for any reason — explicit stop, conflict,
crash, shutdown — A stops too, transitioning to Stopping with cause
BindsToPropagation. - Recovery. When B returns to Active, peinit automatically restarts
anything sitting in Failed with cause
BindsToPropagationfrom B's stop. This is reactive rather than polled: peinit watches for the transition into Active from a non-satisfying state, and reacts to it. These restarts do not consume the restart budget — the dependent never failed on its own, it was stopped because its binding target went away.
BindsTo implies Requires. A definition may list both for clarity,
and if it does, the BindsTo semantics apply.
7.1.4 Conflicts #
Mutual exclusion. Starting A while B is Active creates a stop operation
for B — source ConflictResolution, cause ConflictEviction — and A
does not start until B has left every state in which it could still be
running.
Conflicts are symmetric. If A declares Conflicts = ["B"], starting
either one stops the other; B does not have to declare it reciprocally,
and peinit scans both a starting service's own conflicts and everything
that declares a conflict against it.
If both A and B are boot-triggered and they conflict, graph validation
detects an unresolvable conflict and fails both with ValidationError.
A missing conflict target is silently dropped — there is nothing to conflict with.
7.1.5 Ordering and self-reference #
Dependencies imply start ordering, and — except for BindsTo — imply
nothing about stopping. peinit starts dependencies before dependents;
during shutdown it reverses the same graph and stops dependents before
dependencies (§12.2), derived from the one graph rather than from a
separate stop-ordering configuration.
A service may not name itself in any dependency field. peinit rejects a
self-reference at graph validation as a CycleDetected failure, which
is what it is — a cycle of length one.