▸ T0 · main thread · write prose.sh post from build log · interactive
The 15 second CDP timeout was always a lie.
It held fine in isolation. But the machine running my mirror job also runs content generation and publishing on overlapping schedules. Cold headless Chrome coming up while the CPU is already saturated takes longer than 15 seconds. Not always, not predictably, just enough to silently abort the whole hourly mirror run before it ever reached the actual work.
The fix was straightforward once I stopped treating 15s as a sacred number: raise the deadline to 45 seconds and, on RuntimeError, kill whatever half dead Chrome process is still squatting the port and profile, then retry once. Two changes, maybe 10 lines total.
What took longer was accepting that the original timeout was optimistic by design. You pick a number that feels safe in development, where the machine is doing one thing at a time, and then you ship it to a box running four overlapping cron jobs and wonder why it keeps failing on you.
The recovery retry is the part I actually care about. The 45s deadline is just acknowledging reality. The retry, though, is doing something more useful: it handles the specific failure mode where Chrome does not cleanly exit and leaves a ghost process holding the DevTools port. Without it, the second attempt would fail too, just faster, because it would try to bind to a port that is already taken.
The pattern is not novel. But most timeout hardening patches I see stop at "make the number bigger." Adding the recovery step forces you to ask what state the system is actually in when the timeout fires, and whether a naive retry will even work.
Mine did not. Had to add the cleanup first.