Skip to content
All writing ‹ Part 17 of 18 · A Cache Is a Chain, Not a Box
Engineering · 4 min read

Five Parts Make One Loop

Five small parts make one loop: an expired CDN copy, no bypass rule, stale-while-revalidate, a HEAD refresh that gets 405, and max-age=1 at the edge.

For a large file on the proxy route, every request runs this loop again. In my tests, these were mainly large HTML files.

Each earlier post was only one part. When I connect them, they explain why HTML keeps going back to the origin (Symptom: HTML, CSS, and JS Keep Going to Origin).

browserAkamaiLB cacheproxy 1GETcopy expired 2GET + If-None-Matchcopy also expired 3304 + old copy(stale-while-revalidate) 4HEAD (background) 5405copy stays expired 6200max-age=1fresh for only 1 s next request: the same six steps again
The background HEAD gets 405 every time, so the copy never turns fresh and the next request runs the same six steps again.
  1. The Akamai copy is expired, so it asks the next layer (Cache Freshness: Fresh, Stale, and 304).
  2. The proxy route has no bypass rule, so the LB cache takes the request (A Bypass Header Works Only Where a Rule Reads It).
  3. The LB cache answers 304 at once with the old copy (Stale-While-Revalidate: Serve Old First, Refresh in the Background).
  4. The LB cache refreshes in the background with HEAD. Step 3 and step 4 happen at the same time.
  5. The proxy accepts only GET, so it returns 405 (The Proxy Rejects HEAD, So the Refresh Always Fails). The copy stays expired.
  6. The copy is already expired when it reaches Akamai, so Akamai keeps it for only 1 second.
StepEvidenceType
1, 6The Akamai debug header showed TCP_REFRESH_HIT and max-age=1 three timesFact
4, 57 requests matched 7 lines of HEAD 405 in the proxy log in the same secondFact
3The Age on the 304 is above 3600Inference, because from Taiwan I cannot see the LB cache in the US

When the loop exists, the curl output shows max-age=1 and TCP_REFRESH_HIT. I fetched the same file from the old domain that does not use the proxy. The TTL was normal, and after that every request was a cache hit.

Each part looks reasonable alone. Connected, they make a loop that cannot stop.

Related: Symptom: HTML, CSS, and JS Keep Going to Origin, A Bypass Header Works Only Where a Rule Reads It, Stale-While-Revalidate: Serve Old First, Refresh in the Background, The Proxy Rejects HEAD, So the Refresh Always Fails, What I Learned: A Cache Is a Chain, Not a Box. Or go back to the series overview.

↑↓ navigate ↵ open esc close