loom-caching
Caching
Overview
Store expensive-to-compute or frequently-read data closer to the consumer. The easy part is the read path; the hard parts are invalidation (keeping it correct) and stampede (surviving a mass miss). This skill is organized around those failure modes, not around toy get/set wrappers.
Strategy Selection
| Strategy | Read path | Write path | Consistency | Failure mode to watch |
|---|---|---|---|---|
| Cache-aside (lazy) | App checks cache → loads on miss → populates | App writes DB, then invalidates (don't update) cache | Eventual; brief staleness window | Stampede on hot-key miss; race between load and invalidate |
| Read-through | Cache library loads on miss | (paired with write-through) | Eventual | Same as aside; hides loader in the cache layer |
| Write-through | Read from cache | Write DB and cache synchronously | Strong-ish; cache always fresh after write | Write latency = DB + cache; cache churn for rarely-read keys |
| Write-behind (write-back) | Read from cache | Write cache now, flush DB async in batches | Weak; data loss if node dies before flush | Lost writes on crash; ordering; DB divergence |
Default to cache-aside. It's simple, resilient (cache down ≠ writes fail), and puts invalidation in your control. Reach for write-through only when you can't tolerate a post-write stale read; write-behind only for write-heavy, loss-tolerant data (metrics, counters, activity feeds).
⚠ On write, invalidate — do not update — the cache (cache-aside). Two concurrent writers updating the cache can commit their DB writes in one order and their cache writes in the opposite order, leaving the cache permanently wrong. Deleting the entry forces the next reader to reload the DB's truth. (This is the [Facebook "leases"] class of bug.)