Build1 publisher3 min readPublished
A duplicate process wrote for ten hours because the watchdog compared strings after formatting
An unattended system needed five interventions in two days. None of them printed an error a human would see, because every one left the process running and the watchdog green. The fixes are ordering rules.
The Engineer · Build desk

What happened
- An operator running an automated system on a remote machine with nobody watching it logged five separate interventions in two days, and not one of them produced an error message a human would see.
- One failure was a lost login: the service kept running, kept polling and kept reporting itself healthy while it was no longer authenticated.
- Two of the five failures happened only because something restarted, one of them a config that silently reverted to defaults and left slightly different numbers as its only symptom.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint A check that reports the process is up cannot sit at the top of an alerting stack for an unattended machine, because a deaf poller and an unauthenticated one both satisfy it.
- decision Anyone whose poll loop branches on whether a payload contains items has to decide whether to inspect status first, since a revoked token and a rate limit arrive as errors rather than as an empty list.
- exposure The events least likely to be noticed are exactly the ones this pipeline cannot account for, so whoever depends on the notification learns nothing when a send fails.
The duplicate-process watchdog existed to stop a second copy of the process from starting. It compared strings after formatting instead of before, so the duplicate did not look like a duplicate to it, according to the author of a post on dev.to [5]. Both copies ran side by side for ten hours. Both were writing, and neither complained [4].
Two of the five failures were failures of attachment. A component was still installed and still configured but no longer attached to the thing it was supposed to be attached to, and nothing logged it [7]. A file was written, correct and current, for a consumer that had stopped reading it months earlier [8].
The message loop had the same defect in a different place. It checked whether a response contained items, and went back to sleep when it did not [18]. A revoked token returns an error. So does rate limiting, and so does a second instance stealing the connection [19]. One sleep branch therefore served four conditions: three failures and one genuinely quiet poll [24]. "The process stayed alive, the watchdog stayed green, and the system was completely deaf," the author wrote [20].
The startup-order case is the one with timestamps. The journal shows the component loaded at :29, the value read at :36, and the connection authorized at :39 [13]. The read beat authorization by three seconds [14]. It returned a clean, plausible zero, the system used that zero as a measurement, and it configured itself three hours away from correct [12].
Two of the five interventions happened only because something restarted [10]. The current practice is that every scheduled job writes a heartbeat on every run, including runs where it decided there was nothing to do, and that the absence of a heartbeat for longer than the interval is itself an alert [17]. That rule requires the alerting side to know each job's interval.
The path failure is the cheapest one to reproduce. The author moved a directory; the wrapper script coped because it resolved its own location at runtime, and the registered scheduled tasks failed because they held absolute paths recorded at registration time [15]. The machine said nothing about it [15].
The notification pipeline deleted each event from disk before confirming it had been sent, so a failed send left no event and no retry [22]. "I'd built at-most-once delivery by accident, in the one place where at-least-once was the entire point," the author wrote [23].
Five interventions in two days is one operator's log, and the post does not say what the system does [2][25]. For these failures to be yours, some ordering has to match: your comparison runs after normalization, your scheduler stores absolute paths at registration, your startup reads a remote value before it checks that the connection is usable. The author frames the gap as the one between "automated" and "passive" [1], and states the test this way: "if the only evidence of health is the absence of errors, you have no evidence of health" [26].
What to watch
- Whether the alerting side keeps each job's interval in sync with the scheduler, since the absence-of-heartbeat alert only fires correctly if it knows the interval.
- Whether a second operator publishes the same class of quiet failures with timestamps. That would move this from one log to a measured pattern.
- Whether the scheduler in question records absolute paths at registration by default, which decides how reproducible the path failure is elsewhere.