SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%

# name: caching-strategies description: Designs application-level caching — cache-aside pattern, key naming, TTL policy, invalidation strategy, and stampede protection with Redis or in-process caches. Use when the user asks to add a cache, cache API responses or query results, speed up repeated reads, fix stale-cache or cache-invalidation bugs, or prevent cache stampedes. Do not use for HTTP/CDN edge caching configuration or for database query and index tuning.

# Caching Strategies

# When to use / when NOT to use

  • Use for: adding or reviewing application caches (Redis, Memcached, in-process): what to cache, key design, TTLs, invalidation, failure behavior.
  • Do NOT use for: CDN/Cache-Control edge configuration, database tuning (→ db-skills/optimizing-sql-performance), or memoizing pure functions in code.

# Core rules

  1. Measure before caching. Cache only reads that are demonstrably hot AND expensive; record the baseline latency and expected hit rate first. A cache below ~80% hit rate usually adds complexity for nothing.
  2. Cache-aside is the default pattern: read cache → miss → read origin → write cache with TTL. Write-through/write-behind only when a measured write-path need exists.
  3. Every key has a TTL — no immortal keys. TTL is the invalidation of last resort; without it, every bug becomes permanent.
    • SETEX product:v1:42 300 …
    • SET product:42 … (lives until someone remembers it exists)
  4. Choose the invalidation strategy per data class, at design time:
    • tolerates staleness → TTL-only (pick the tolerance as the TTL)
    • must reflect writes → purge/update on write (delete the key in the write path)
    • broad derived data → versioned keys (bump v in the key; old entries age out) Mixing strategies ad hoc is how stale-forever bugs are born.
  5. Key schema is part of the design: entity:version:id[:variant], e.g. product:v2:42:fr. Every dimension that changes the value appears in the key — locale, currency, role.
  6. Never serve one user's data from a shared key. Per-user data gets the user ID in the key; better, don't cache authorization decisions at all.
    • GET profile:current — whoever primed it wins
  7. Protect against stampedes: jitter TTLs (±10%) so keys don't expire in sync, and use a single-flight lock so one process rebuilds a hot key while others serve slightly-stale or wait.
  8. Cache down ≠ site down. Wrap cache calls with a short timeout (~50 ms) and fall through to origin on any cache error; a cache outage becomes a latency event, not an availability event.

# Workflow

  1. Identify the hot, expensive read; record baseline latency and expected hit rate.
  2. Classify its data (staleness tolerance) and pick the invalidation strategy from rule 4.
  3. Define the key schema and TTL (+ jitter); implement cache-aside with origin fallback on cache errors.
  4. Add hit/miss metrics per key family.
  5. Validate: write to the origin and confirm the read path reflects it within the chosen tolerance; kill the cache and confirm requests still succeed from origin; check hit rate after a warm-up period against the target.

# Edge cases & failure modes

  • Caching negative results (not-found) — allowed with a SHORT TTL (~30 s) to absorb miss storms, but must be purged on create.
  • Large values (>100 KB in Redis) — compress or split; big values evict everything else.
  • Cold start after deploy/flush — expect an origin load spike; single-flight (rule 7) is what keeps it survivable.
  • Two caches for one datum (in-process + Redis) — layered TTLs multiply staleness; keep the in-process layer very short (~1–5 s).

# References

Snippets for single-flight, jitter, and key-schema helpers: see references/patterns.md.