Cache invalidation that just happens.
The second-hardest problem in computer science, solved by reading the write-ahead log: every committed change reaches the cache in order, and a delete removes the key.
The problem
Caches go stale because the code path that writes the database and the code path that writes the cache are two code paths. Someone forgets one, a batch job bypasses the application, a migration rewrites rows, and the cache lies until the TTL expires.
How it works with Waltail
The Redis cache sink makes the database the only writer: an insert or update SETs prefix + schema.table:pk to the change JSON, a delete DELs it. Because changes to one row are applied in commit order, the cache always converges on the latest state. Your application reads through on a miss and never writes the cache itself.
If you would rather keep your own cache shape, use Redis Streams or a queue and write a small consumer that invalidates exactly the keys you care about.
What to watch
- The cached value is the whole change envelope; the current row is under
data. - Keys are written without a TTL; set your own eviction policy if the keyspace is unbounded.
Sinks for this
Redis cache
SET on change, DEL on delete
Redis Streams
XADD, consumer groups
Webhooks
Any HTTPS endpoint
Questions
Does this replace TTLs?
For correctness, yes — the cache reflects the database within about a second of commit. Keep a long TTL as a safety net if you like.