The key is the dependency list
Write out what a cached value was computed from — every input, every flag, every piece of ambient state the code read without mentioning it — and you have written the key. If the list is complete, the key is correct by construction. If something is missing, you have not built a cache, you have built a way of serving one user's answer to another.
That reframing is most of the work. It turns an invalidation problem, which is about time and is therefore hard, into a naming problem, which is about being honest and is merely tedious.
Invalidation is a question about everything the cached answer was derived from, and about which of those inputs can change without anyone announcing it.
What that looks like here
The generator that built this page keys a rendered page on its own bytes, the config, the theme, and the set of icon files the capsule ships. That last one is not obvious, and it was not there at first: adding a favicon changes the head of every page, so a key that ignored it would serve pages from before the favicon existed, forever, with no way to notice.
Nothing in that key is a timestamp. A modification time answers a question nobody asked — it says when a file was touched, not whether what it says is still true — and a fresh checkout rewrites every one of them without changing a byte of content.
- The seven line types this site is built from
- How this page works, and why the markers are not really there
The failure mode is the interesting part
An under-specified key does not crash. It serves a wrong answer at full speed, with no error and no log line, and it keeps doing it until somebody notices by eye. That is why the honest move is to make the key say too much rather than too little: an over-specified key costs you a cache miss, which shows up in a graph, and an under-specified one costs you correctness, which does not.
Back to the posts