01
The failure was a system, not a server
The first signal was familiar: CPU saturation, slow PHP workers and pages that stopped completing. Restarting the worker pool restored service, but that did not explain why the origin could not recover on its own.
Two traffic shapes mattered. Uncached requests created the initial pressure. At the same time, a dependent application fetched shared WordPress fragments. As the origin slowed, those fetches timed out, failed to populate cache and were attempted again. The dependent application became an amplifier.
02
Build one timeline across the stack
CDN logs, origin access logs, PHP slow logs and infrastructure metrics were aligned on one timeline. That separated the trigger from the amplifier and ruled out several plausible distractions, including a deploy, a cache flush and an administrative action.
The health check also told an incomplete story. It observed a cached public page, so it stayed green while the uncached origin path was saturated. A health check is only useful when it exercises the failure mode that matters.
03
Remove the feedback loop
The shared fragments were given an origin cache with locking, background refresh and stale-on-error behaviour. Edge controls challenged the abusive request pattern before it reached PHP. The recovery path was then tested against the origin and through the CDN.
This reduced repeated rendering work and allowed the system to serve a last-known-good fragment while WordPress refreshed in the background. The incident response moved from restarting a process to changing the load path.
04
The operating lesson
A traffic spike is not a complete root cause. Production recovery needs a causal model: trigger, amplifier, failed guardrail and safe intervention. The same model applies to queues, webhooks, API retries and cache stampedes.
The strongest fix removes amplification first. Capacity can still matter, but more capacity only delays the next failure when the architecture keeps multiplying work.