cconnected.
Understand the pattern. Find your own way.Find your starting point
Your learning feed/Idea 199 of 218
Ideas this builds on
High-level design199 / 218

Keep a nearby copy with an expiry story

Picture

On a cache hit, return the saved value. On a miss, read the source of truth and fill the cache. That is cache-aside.

Predict

Does a long TTL guarantee that cached data is correct until it expires?

Walk through the small example

No, the source can change earlier. TTL bounds retention, not agreement with every intervening write.

Mental model and runnable Python model

State the cache’s owner, key, TTL, eviction policy, and stale-read tolerance. Cache-aside is simple, but invalidating after a write can race with an earlier slow reader that repopulates an old value. Versioned keys, conditional fills, or stronger coordination may be needed. Write-through and write-behind move different consistency and failure responsibilities into the cache. Separate CDN caching of suitable responses from per-user application caches. Negative caching and hot-key protection also need bounded lifetimes.

What the function promises: TTLCache uses caller-supplied monotonic times and caches successful loader results, including None. It is single-threaded, unbounded, and not a complete invalidation protocol.

class TTLCache:
    def __init__(self, ttl):
        if ttl <= 0:
            raise ValueError("TTL must be positive")
        self.ttl, self.entries = ttl, {}
    def get(self, key, now, load):
        if key in self.entries:
            value, expires = self.entries[key]
            if now < expires:
                return value
        value = load(key)
        self.entries[key] = (value, now + self.ttl)
        return value
    def invalidate(self, key):
        self.entries.pop(key, None)

source = {"a": 1}
cache = TTLCache(5)
assert cache.get("a", 0, source.__getitem__) == 1
source["a"] = 2
assert cache.get("a", 4, source.__getitem__) == 1
assert cache.get("a", 5, source.__getitem__) == 2

Work and storage: Expected O(1) cache lookups; misses pay source cost. Memory grows with keys unless eviction or expiry cleanup is added.

When to recognize it: If many requests miss together, all may hit the database. Single-flight work, jittered expiry, or controlled stale serving can reduce that stampede.

Check before applying it: Cache-aside needs a stated stale-read and invalidation policy, especially under concurrent writes.

Change one rule

A slow miss started before an update, then fills the cache after invalidation. Can stale data reappear?

See what changes

Yes. Invalidate-after-write alone does not prevent that race. Use a version or generation check on fills, or another protocol matching the required freshness guarantee.

Connect

Choose storage from reads and writes: The database remains authoritative under a defined caching protocol.

LRU Cache: LRU chooses what to evict; TTL and invalidation decide freshness.