Guide implementing TTR-based in-memory cache eviction with clock-safe time comparison and deployment jitter
How this skill is triggered — by the user, by Claude, or both
Slash command
/puzzle9900-claude-plugin:generic-cache-evictionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Any time a cache mechanism is created, it **must** include eviction. This skill enforces a consistent, clock-safe TTR (time-to-refresh) eviction strategy for in-memory caches. It applies across all platforms (Android, iOS, backend, web).
Any time a cache mechanism is created, it must include eviction. This skill enforces a consistent, clock-safe TTR (time-to-refresh) eviction strategy for in-memory caches. It applies across all platforms (Android, iOS, backend, web).
You are a cache implementation reviewer and guide. When invoked, walk the developer through building eviction correctly for their cache.
Before writing any code, ask the developer:
Default TTR: What is the default time-to-refresh for this cache?
5m, 15m, 1h, 24hSize limit (optional, recommend asking): Should the cache have a max entry count?
Do not use:
currentTime - storedTime > TTR // breaks if clock moves backward (negative result)
Always use the absolute value of the time difference to handle:
elapsed = abs(currentTime - storedTimestamp)
isExpired = elapsed >= effectiveTTR
effectiveTTR = TTR + jitter (see Step 3)
Always use the user device time (wall clock as set by the user). Reasoning:
Jitter prevents a deployment (or a batch of cold starts) from expiring all cache entries simultaneously, causing a thundering herd of refreshes.
[0, jitterMax]jitterMax: 5 minutes (adjust if TTR is very short, e.g., use TTR * 0.1 if TTR < 10m)jitter = random_uniform(0, jitterMax) // computed once, stored at write time
effectiveTTR = TTR + jitter
// At write:
entry = { value, storedTimestamp: now(), effectiveTTR }
// At read:
elapsed = abs(now() - entry.storedTimestamp)
if elapsed >= entry.effectiveTTR:
evict and refresh
Every cache entry must carry at minimum:
CacheEntry {
value: <cached data>
storedTimestamp: <device wall clock at write time>
effectiveTTR: <TTR + jitter, computed at write time>
}
If size limit is enabled, also track:
lastAccessedAt: <timestamp of last read, for LRU eviction>
Check eviction at read time (lazy eviction). Do not run background sweeps unless the cache is long-lived and can grow unboundedly.
function get(key):
entry = store[key]
if entry is null:
return MISS
elapsed = abs(now() - entry.storedTimestamp)
if elapsed >= entry.effectiveTTR:
store.remove(key)
return MISS // caller fetches fresh value and calls put()
return entry.value
function put(key, value, ttr, jitterMax = 5min):
jitter = random_uniform(0, jitterMax)
store[key] = CacheEntry(
value = value,
storedTimestamp = now(),
effectiveTTR = ttr + jitter
)
If size limit is enabled, after put():
if store.size > maxEntries:
evict entry with the smallest lastAccessedAt (LRU)
Before considering the cache implementation complete, confirm:
storedTimestamp and effectiveTTRabs(now() - storedTimestamp) >= effectiveTTR[0, jitterMax]abs(), random_uniform(), and now() to the target language's standard librarynpx claudepluginhub puzzle9900/puzzle9900-claude-plugin --plugin puzzle9900-claude-pluginProvides cache invalidation strategies: TTL-based expiry, event-driven invalidation, versioned keys, stampede prevention, and fan-out invalidation for denormalized data.
Assesses caching opportunities and implements multi-layer strategies with Redis/Memcached/CDN, including cache-aside patterns, TTL/event invalidation, and stampede prevention.
Implements Redis caching patterns like cache-aside, write-through, write-behind; covers Memcached, invalidation strategies, TTL design, stampede prevention, CDN config, distributed caching. For optimizing read performance, reducing DB load, designing cache layers.