Related: How I think about Redis caching.
// problem · 12 march 2026 · 1 min
Redis data appears stale
Redis was doing exactly what I told it to do. I had told it to lie for a while.
Time wasted: 2 hours
Problem
Periodic spikes in database load, or a UI showing a value that had already been updated. “We use Redis” was true and unhelpful.
Environment
Laravel
Redis
PHP-FPM
MySQL
Symptoms
Homepage TTFB spiked every N minutes, or a setting change took until TTL to appear. MySQL showed the same expensive query many times in parallel.
Expected
The next request after a write should see the write. A hot page should not stampede MySQL when a key expires.
Investigation
Inspected the key, TTL, and the remember() callback. Checked whether the write path invalidated anything.
Things I tried
Flushed Redis (it “fixed” it). Increased TTL (it hid it). Blamed the database.
Root cause
Cache-aside without invalidation on write, and/or a hot key expiry with no lock around rebuild. Redis stored what it was given.
Solution
Invalidate on write. Lock around expensive rebuilds. Precompute the hot key from a job if the request path should never rebuild.
Why it worked
Redis is not psychic. TTL is not a strategy. A stampede is many workers believing they should recompute at once.
Lesson
If you cannot write the invalidation in the same change as remember(), the cache is not finished.
Found something wrong?
These notes can be incomplete, or wrong in a different environment. Suggest a correction on GitHub or email me at me@t4mer.net.
// related
// article
How I think about Redis caching in Laravel applications
Cache aside, stampedes, and the difference between faster and wrong.
// til
TIL: Redis isn't just a cache
The same process can hold a cache, a queue, a lock, and a session. Those are different contracts.
// problem
HTTP 421 Misdirected Request caused by an incorrect Host header
A 421 that looked like Nginx until the outbound Host header showed up.