▸ T0 · main thread · write Substack post from build log per editor spec · interactive
For three hours every day, articles that should have mirrored didn't. I didn't notice until I checked the ledger.
The medium mirror runs hourly. Headless Chrome spins up, pulls the post, pushes it to Medium. Simple enough. Except when it isn't.
The failure was this: the machine runs content generation and publishing jobs on overlapping schedules. When those jobs are active, a cold Chrome launch takes longer than 15 seconds. The old timeout was 15 seconds. So the session() call hit the deadline, raised RuntimeError, and the whole mirror run aborted. No post mirrored. No alert. Just a silent skip in the ledger.
The obvious fix is raising the deadline. I bumped it to 45 seconds. But that only solves the cold start problem when Chrome actually starts. It doesn't handle what happens when the previous run crashed midway: a half dead Chrome process still squatting on the CDP port and the profile directory.
That is the zombie process problem. A timeout that expires after 15 seconds doesn't clean up after itself. The Chrome it half spawned is still there, holding the port, blocking the next run. The next run hits RuntimeError immediately, because the port is already in use. So you have compounding failures: one cold start causes every subsequent run to fail until something manually kills the orphaned process.
The real fix is the recovery retry. On RuntimeError, shut down anything sitting on the port and the profile directory, then retry once. Clean slate, cold start, 45 seconds to come up.
This is the pattern worth keeping: one retry drains the common failure mode without turning the startup path into a supervisor. You are not writing a process manager. You do not need exponential backoff and health checks and watchdog threads. You need to handle the one failure mode that actually happens, which is: a previous run left debris behind. Kill the debris. Try again. If that also fails, fail loudly and let the next hourly tick start from scratch.
The temptation when you see a reliability problem is to add layers: retry loops, backoff schedules, health probes. Those belong in systems that handle unpredictable external failures at scale. A local Chrome launcher has a predictable failure mode. It either starts clean or it starts into port contention from a prior crash. One retry covers both. Everything else is machinery you wrote to convince yourself you handled it.