Requires= tells systemd two things: this unit needs that one to exist, and if that one stops, stop this one too. It says nothing about what happens when the required unit comes back. That gap — obvious in the documentation, invisible in production — cost one of our systems eight days of downtime that nobody noticed until someone tried to log in and got a 502.
What Requires= actually promises
The setup was reasonable, and it still is. A backend service depends on its database:
[Unit]
[email protected] This is correct. You don't want an application server running with no database underneath it, serving errors to every request instead of failing cleanly. Requires= enforces exactly that: if PostgreSQL stops, systemd stops the dependent service right along with it, in the right order, no exceptions.
The mistake isn't in writing this line. The mistake is in what you assume it also does.
The night nothing was wrong until it was
A routine, fully automated security patch triggered a PostgreSQL package update at 3:30 in the morning — the kind of unattended maintenance that runs on every properly patched Linux server, every night, without anyone watching. Systemd did exactly what it was told: it stopped the application service first, then stopped PostgreSQL, in the correct dependency order. PostgreSQL restarted cleanly a few seconds later, new package version in place, no errors in its own log.
The application never came back.
Nothing crashed. Nothing threw an exception. The service simply stayed in the state systemd had put it in — stopped, deliberately, correctly, on purpose — and there was no instruction anywhere telling it to start again once its dependency was healthy. It sat there for eight days. Every request during that window hit a working reverse proxy pointed at nothing, and returned a clean, boring 502.
Nobody found this through a dashboard. It was found by someone personally hitting the failure — trying to use the product and getting an error page.
The alert that fired and was ignored anyway
Here's the part that matters more than the systemd bug itself: there was a monitoring system, checking the site every five minutes, and it correctly flagged the outage within minutes of it starting. An alert email went out immediately. It sat in an inbox for the entire eight days, unread, deleted along with the routine daily status digest that arrives from a similar-looking sender every single day regardless of whether anything is wrong.
Fixing this wasn't a matter of adding more monitoring. The monitoring was already right. The fix was making the one email that means something impossible to mistake for the ninety that don't — a filter that stars it, labels it, marks it important, so a real failure can never again be shaped exactly like an ordinary Tuesday.
A system that correctly detects a failure and then gets ignored has the same practical outcome as a system with no detection at all.
PartOf=, and the general shape of the mistake
The actual fix is small. Systemd has a second directive, PartOf=, that does something Requires= does not: it propagates both the stop and the restart of the target service onto the dependent, not just the ordering.
[Unit]
[email protected]
[email protected] With both lines present, the next time PostgreSQL restarts for a routine patch, the application restarts with it — automatically, the same night, with nobody watching for it. The eight-day gap becomes structurally impossible instead of merely unlikely.
The broader shape of this mistake generalizes past systemd. Any time you declare that one thing depends on another, ask which half of the relationship you actually specified. Did you define what happens when the dependency goes down — or also what happens when it comes back? A message queue consumer that reconnects on failure but never resumes its subscription. A circuit breaker that opens correctly but has no path back to closed. A container orchestrator's liveness probe that restarts a crashed pod but not the sidecar that crashed with it. In every one of these, "A depends on B" quietly meant "A depends on B going down," with the other half of the relationship — B coming back — left as an assumption nobody wrote down and nobody tested.
What this means in practice
Read every declared dependency for what it actually specifies, not what it feels like it should imply. Test the recovery path deliberately — stop the thing you depend on, let it come back, and confirm your own service comes back with it, rather than only testing that it goes down safely. And treat an alert that looks identical to routine noise as a design failure in the alert itself, not a discipline failure in the person who was supposed to notice it.
The eight days weren't caused by carelessness. They were caused by a dependency that was half-specified and a signal that was indistinguishable from silence. Both are fixable in an afternoon, once you know to look for them.