This Week I Learned: Public versus Private Cache-control [2022–09–23]

Peter Brownlow
2 min readSep 23, 2022
Photo by Dayne Topkin on Unsplash

This was something that appeared quite mysterious and occasional at first, but seems to have a very simple explanation in the end.

(This is a software engineering story.)

I had a REST API that very occasionally returned results to the wrong user. Logging confirmed that this never happened inside my service, only in what the user saw. Logging also showed that sometimes a request was returned without my service being actually called, but that’s OK because there are various caches between what we see on the screen and what happens inside the service’s back end.

Data being shown to the wrong user is pretty bad. Right now we have only 2 users on this service and I’m one of them there is no harm being done yet, but obviously it can’t continue. I needed to fix it!

Unfortunately, reproducing the problem was frustratingly elusive. It just wouldn’t happen repeatedly. I’m talking a couple of requests per week and then nothing the next week. I could retrospectively see it in my front end monitoring but I couldn’t deliberately trigger it.

Then one day I was chatting with the other user while we were both looking at the same screen at the same time and suddenly his content changed to what I saw. A light bulb went off in my head. I went to my code and searched everywhere for “cache” and just kept going to the next hit until I saw this:

Cache-Control: public, max-age=604800, stale-while-revalidate=86400

Dammit, why is that public there? I didn’t remember why I put that there. Is that OK on this endpoint?

Definitely NOT:

Responses for requests with Authorization header fields must not be stored in a shared cache; however, the public directive will cause such responses to be stored in a shared cache.

I had accidentally put public instead of private on a response that only logged-in users can see and is user-specific. This told networking equipment between my back-end code and the browser that it was OK to cache this response and serve it up to another request to the same URL.

So why was it intermittent?

This is (still) a toy-sized service so I’m guessing that whatever rules are used to figure out what to cache and for how long correctly show that it’s not a high-value item to retain… except when me and the other user are sitting at our browsers at the same time furiously hammering our refresh keys.

Future crisis averted!

--

--

Peter Brownlow

Software builder, people manager, topical deep-dive enthusiast