Best for
- ALWAYS use when designing, reviewing, or troubleshooting Redis caching layers — cache pattern selection (cache-aside, write-through, write-behind), TTL strategy, cache stampede/penetration/avalanche prevention, hot key…
johnqtcg/awesome-skills/skills/redis-cache-strategy/SKILL.md
Redis caching strategy designer and reviewer. ALWAYS use when designing, reviewing, or troubleshooting Redis caching layers — cache pattern selection (cache-aside, write-through, write-behind), TTL strategy, cache stampede/penetration/avalanche prevention, hot key handling, cache-DB consistency, distributed locking, key naming, and degradation design. Use even for "just add a cache" requests — cache invalidation is one of the two hard problems in computer science, and a naive implementation crea
Decision brief
Redis caching strategy designer and reviewer. Use even for "just add a cache" requests — cache invalidation is one of the two hard problems in computer science, and a naive implementation crea
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/johnqtcg/awesome-skills --skill "skills/redis-cache-strategy"Inspect the Agent Skill "redis-cache-strategy" from https://github.com/johnqtcg/awesome-skills/blob/d933bc88237f7a18a7ecf01e5d97a745b083df0f/skills/redis-cache-strategy/SKILL.md at commit d933bc88237f7a18a7ecf01e5d97a745b083df0f. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Review the “9.2 Depth & Mode [Lite/Standard/Deep] × [review/design/troubleshoot] — rationale” section in the pinned source before continuing.
Review the “9.3 Risk Assessment | Component | Pattern | Risk | Notes |” section in the pinned source before continuing.
Review the “9.5 Implementation key schema, TTL config, code patterns” section in the pinned source before continuing.
§1 scope · §2 gates (context, mode, risk, completeness) · §3 depth · §4 degradation modes · §5 the checklist — the only item list · §6 pattern selection · §7 anti-example index · §8 how §5's items are scored · §9 output contract · §10 which reference to load when.
In scope — Redis caching strategy for production backend services. The §5 checklist is the scope; it is not restated here, because a second copy of a list is the defect this skill spent a release removing.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 30 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
§1 scope · §2 gates (context, mode, risk, completeness) · §3 depth · §4 degradation modes · §5 the checklist — the only item list · §6 pattern selection · §7 anti-example index · §8 how §5's items are scored · §9 output contract · §10 which reference to load when.
References: cache-patterns.md (patterns in depth) ·
cache-failure-modes.md (stampede / penetration / avalanche / hot key) ·
distributed-locks.md (fencing, renewal, failover) ·
cache-anti-examples.md (AE-1 … AE-13 with code) ·
redis-version-matrix.md (what each Redis version changes).
In scope — Redis caching strategy for production backend services. The §5 checklist is the scope; it is not restated here, because a second copy of a list is the defect this skill spent a release removing.
Out of scope — delegate to dedicated skills:
redis-best-practisego-code-reviewer or language-specific reviewerredis-best-practiseExecute gates sequentially. Each gate has a STOP condition.
| Item | Why it matters | If unknown |
|---|---|---|
| Redis version (major.minor) | Gates several concrete answers this skill gives — see below | Never assume a version. Answer in branches, or mark the version-gated item NOT SCOREABLE |
| Deployment mode (standalone / sentinel / cluster) | Affects key distribution, Lua atomicity scope, lock patterns | Assume standalone — but not for a lock or a multi-key script, where Cluster changes correctness (§5 S7) |
| maxmemory + eviction policy | Determines what happens when cache is full | Ask; critical for correctness |
| Cache role in architecture | Primary cache? L1/L2? Read-through proxy? | Blocking — cannot be assumed |
| Data source type | SQL DB / NoSQL / external API — affects consistency patterns | Blocking — cannot be assumed |
| Read:write ratio | Drives pattern selection (read-heavy → cache-aside; write-heavy → write-behind) | Assume read-heavy |
| Consistency requirement | Eventual (seconds)? Strong? Best-effort? | Blocking — cannot be assumed |
| Peak QPS on cached entities | Determines stampede/hot-key risk | Assume high if unknown |
The three blocking items block because a wrong guess is invisible: a strategy built on an assumed consistency requirement reviews clean and surfaces only as an incident.
The remaining five are not uniformly safe to default — the "If unknown"
column is the authority. Only read:write ratio and peak QPS degrade to a tuning
problem when wrong. Version has no default (below). maxmemory must be asked:
noeviction on a full instance turns every cache write into an error, which is
C3's problem. Deployment mode defaults to standalone only while nothing in scope
is a lock or a multi-key script — under Cluster those need a shared hash slot
(S7), so a wrong default there is a correctness defect too.
Version is gated per conclusion, not globally. A global default (the old
"assume 6.0") is wrong in both directions — it invents constraints that no longer
apply and hides features that are now the better answer. Ask, or state both
branches, when a conclusion touches: per-field Hash TTL (HEXPIRE, 7.4+);
hash-max-listpack-* naming and encoding (7.0+, before that
hash-max-ziplist-*); a deletable membership filter (CF.* cuckoo, bundled
8.0+); keyspace events OVERWRITTEN / TYPE_CHANGED (8.2+, best-effort only —
C2); Lua-free compare-and-set / compare-and-delete (SET … IFEQ, DELEX … IFEQ,
8.4+); HOTKEYS and *-lrm eviction (8.6+); the Hash-vs-String memory trade
(compact hashes, 8.10+). Matrix and unknown-version procedure:
references/redis-version-matrix.md.
STOP — emit a question list and stop — when any of cache role, data source, or consistency requirement is unknown. You may then output a numbered list of what you need and why, plus (if code was supplied) a Minimal-mode static review of that code as written (§4). You may not output a strategy design, a pattern recommendation, or a scorecard.
PROCEED: all three blocking items are stated by the user or derivable from
supplied code/config. The remaining five may use their "If unknown" defaults;
each default used appears in §9.1 with Source = assumed and in §9.9 with the
impact if it is wrong.
| Mode | Trigger | Output |
|---|---|---|
| review | User provides existing caching code/config | Safety analysis with findings |
| design | User describes what they want to cache | Complete cache strategy proposal |
| troubleshoot | User reports cache-related issues (stale data, stampede, latency) | Root cause + fix plan |
STOP: Request is not cache-related (e.g., Redis Streams pipeline, pub/sub messaging). Redirect to redis-best-practise.
PROCEED: Caching intent confirmed.
| Risk | Definition | Required action |
|---|---|---|
| SAFE | Standard cache-aside with TTL, read-heavy workload | Standard review |
| WARN | Distributed lock usage, write-behind pattern, multi-service cache sharing | Off-peak rollout + monitoring |
| UNSAFE | Cache as sole data source (no DB backing), or cache-DB consistency SLA < 1s | Architecture review + fallback design mandatory |
STOP: Any UNSAFE item without fallback design.
PROCEED: Every cache component has risk level and mitigation.
Before delivering output, verify all §9 Output Contract sections present. §9.9 Uncovered Risks must never be empty.
| Depth | When to use | Gates | References to load |
|---|---|---|---|
| Lite | Single key TTL/pattern review, ≤3 cached entities | 1–4 | None |
| Standard | Full cache layer design (pattern + consistency + failure modes) | 1–4 | cache-patterns.md |
| Deep | Multi-service cache architecture, hot key analysis, consistency SLA | 1–4 | cache-patterns.md + cache-failure-modes.md |
distributed-locks.md loads on the presence of a lock, at any depth.
Force Standard or higher on any of: write-behind or write-through pattern, distributed lock, multi-service shared cache, consistency SLA < 5s, cache as authoritative store for any data, hot key with >10K QPS.
When context is incomplete, degrade gracefully — never fabricate assumptions about consistency requirements.
| Available context | Mode | What you can do | What you cannot do |
|---|---|---|---|
| Full (version, mode, eviction, source, consistency SLA) | Full | Complete strategy with quantified staleness | — |
| Source + consistency known, infra unknown | Degraded | Pattern selection + consistency design; flag infra unknowns | Eviction/memory recommendations |
| Only code snippets, no architecture context | Minimal | Static review of caching patterns in code | Full strategy design |
| No code (greenfield design request) | Planning | Propose cache strategy from requirements | Review existing implementation |
Hard rule: Never claim a caching strategy is "consistent" without defining the staleness window. In Degraded/Minimal mode, flag "consistency SLA undefined" in §9.9.
The only list of items in this skill. §8 scores these same IDs and defines nothing of its own, so an item cannot be graded in one place and ignored in the other. Mark every item with exactly one verdict:
| Verdict | Meaning | Effect on the score |
|---|---|---|
| PASS | Evidence in the design or code satisfies the item | numerator + denominator |
| WARN | Present but partial, unverified, or weaker than the item requires | denominator only — a WARN is not a pass |
| FAIL | Absent, or contradicted by the code | denominator only |
| N/A | Structurally inapplicable (no lock exists at all; single-tenant system) — requires a one-line reason naming the structural fact | removed from both |
| NOT SCOREABLE | The context needed to judge is missing (§4 Degraded / Minimal / Planning) | removed from both, and caps the verdict — §8 |
Silence is FAIL, not N/A. A design that never mentions degradation has no degradation path. N/A is for items the system cannot have, never for items the author did not discuss — otherwise the denominator shrinks until all pass.
C1 — Source of truth explicitly defined. DB or cache authoritative? Ambiguity here is the #1 cause of inconsistency bugs. The database is almost always the source of truth; the cache is a derived, disposable copy.
C2 — Invalidation strategy defined and non-blocking. At least one
authoritative mechanism must be active: TTL expiry, explicit invalidation on
write, or a durable event stream (CDC / transactional outbox). "Write both and
hope" is not one. It must not depend on a blocking keyspace scan: KEYS stalls
every other client (AE-4). Pattern choice (cache-aside / write-through /
write-behind / dual-write debounce) must match the read:write ratio and the
consistency requirement; load references/cache-patterns.md when uncertain.
Redis keyspace notifications do not count as that mechanism. They are
Pub/Sub, which Redis documents as fire and forget (a subscriber that
disconnects loses every event from that window, permanently); in Cluster they
are node-local and not broadcast; and they report that a Redis key changed,
not that a database row did. Best-effort L2→L1 invalidation only, always
behind a TTL floor — see references/redis-version-matrix.md § 8.2.
C3 — Cache-write failure semantics stated. What the system guarantees when
the SET/DEL itself fails: best-effort + TTL, bounded retry, transactional
outbox, or CDC. "We DEL on failure" is not an answer — the DEL is the operation
that failed. If the staleness SLA is shorter than the TTL, best-effort is a FAIL.
C4 — Redis outage distinguished from cache miss in code. redis.Nil is a
miss; every other error is an outage. An operational error that falls through to
the data source as if it were a miss converts the outage into a full-rate
stampede.
C5 — Cache-down degradation path exists. What the service does with Redis unavailable: serve stale from L1, bypass to the DB with rate limiting, or return a degraded response. "Service crashes" is not an acceptable answer.
C6 — Durability profile matches the data. Write-behind — and every other deferred-durability path — puts an RPO > 0 on the data. Financial, ledger, or audit-critical data therefore needs a durable queue with acknowledgement and a written, accepted RPO. A fire-and-forget goroutine between cache and DB is a FAIL, not a WARN: the process dying is not an edge case, it is a deploy.
C7 — Tenant and principal isolation in the key. Any key holding data scoped to a tenant, user, or permission set must carry that scope in the key. A key built from the entity ID alone is reachable by every caller that reaches the cache path, making the cache an authorization bypass that correct DB-side authorization cannot undo. The cached value must likewise not carry fields the requester is not entitled to see.
C8 — Every cached key has a bounded lifetime. A TTL, or a documented and enforced invalidation guarantee that makes immortality safe. Without one a single missed invalidation is stale forever rather than until expiry — unbounded staleness is a correctness defect, not a tuning problem.
S1 — TTL jitter applied per write. Random ±10–20% computed at write time, per key, so keys populated together do not expire together. A constant randomised once at startup shifts the avalanche instead of spreading it.
H1 — Key naming follows a namespace convention. {service}:{entity}:{id} or
{tenant}:{domain}:{version}:{id} — deterministic, greppable, collision-free, no
bare numeric IDs. (Naming style is hygiene; the isolation guarantee is C7.)
H2 — Key and value size bounded. Keys < 1KB, values < 10KB as default
guidance; check with redis-cli --bigkeys. Over the bound, pick the structure by
access granularity and then measure — do not reach for a Hash reflexively:
HGETALL costs more than GET and you lose the ability to compress across fields.HGET/HMGET) → a Hash avoids transferring the rest, which is the real win.hash-max-listpack-entries (default 512) and hash-max-listpack-value (default 64 bytes) — that is the listpack encoding (named hash-max-ziplist-* before 7.0). Cross either threshold and it converts to a hashtable, where per-field overhead makes it larger than the equivalent String. A "large blob" is by definition past the 64-byte value threshold, so the memory argument does not apply to it at all. On 8.10+ compact hashes store shared field names once, which narrows but does not erase the gap — measure on your version.HEXPIRE, which is Redis 7.4+. Below that a Hash has one TTL for the whole key, so splitting an object into fields forces every field to share one expiry — often the reason a Hash is the wrong choice.MEMORY USAGE <key> and OBJECT ENCODING <key> on real data before committing to a shape.H3 — Eviction policy matches access pattern. allkeys-lru general,
volatile-lru for mixed TTL/permanent keys, allkeys-lfu frequency-based
(4.0+), allkeys-lrm/volatile-lrm least-recently-modified (8.6+). A full
instance under noeviction turns every cache write into an error — that is C3's
problem, not a tuning one.
S2 — Stampede (thundering herd) protection. A hot key expires and every concurrent request queries the DB at once. Defense: singleflight / mutex (one caller fetches, the rest wait), stale-while-revalidate, or probabilistic early expiration.
S3 — Penetration protection. Requests for IDs that do not exist bypass the
cache and always reach the DB. Defense: cache the null result with a short TTL
(30–60s), or a membership filter — whose rebuild semantics must be stated,
because a plain bloom filter cannot delete and answers "definitely absent" for
rows inserted since the last rebuild, turning the cache into a source of wrong
404s. Cuckoo filters (CF.*, bundled from 8.0) support deletion.
S4 — Avalanche protection. Mass expiry at one instant moves the whole read load to the DB in a single step. Defense: TTL jitter (S1), L1 local cache, circuit breaker on DB calls. Keys populated by one warmup batch share a population time, so the jitter must be at least as wide as that batch.
S5 — Hot key mitigation. One key taking disproportionate traffic. Defense:
L1 in-process cache, replica fan-out, or read replicas. Detect with
redis-cli --hotkeys (4.0+, LFU mode) or the server-side HOTKEYS command
(8.6+, top-K by CPU time and network bytes).
Replica fan-out means N physical copies of one logical key, and the replica
index must be chosen by the caller — round-robin or random, per request.
Deriving it from the key (key:{hash%N}) is the classic non-fix: the hash is
deterministic, so every reader computes the same replica and 100% of the traffic
still lands on one key on one node. Fan-out also obliges you to write and
invalidate all N replicas and to state its consistency cost — see
references/cache-failure-modes.md.
S6 — Staleness window quantified. How stale may cached data be, in seconds/minutes? A business decision, not a technical default. Layers add up: an L1 TTL of T stacks on top of the Redis TTL because every process holds its own copy. Publish the total and monitor the actual value.
S7 — Distributed lock is well-formed and bounded. Baseline: a TTL so a
crashed holder cannot deadlock it, a unique per-acquisition token, and a
compare-and-set release (Lua CAS, or DELEX <key> IFEQ <token> on 8.4+) so you
cannot delete someone else's lock. Beyond it: keep the critical section well
under the TTL or renew with a hard cap — unbounded renewal turns a hung holder
into a permanent lock, worse than the deadlock the TTL prevented; treat a failed
renewal as a lost lock and abort; state a failover position, since asynchronous
replication can grant one lock twice. In Cluster every key a lock script touches
must share a hash slot, or it fails with CROSSSLOT.
C9 — Correctness locks are enforced where the data lives. When the lock
guards an effect outside Redis (a DB row, a payment, a file, a third-party call),
a fencing token must be issued atomically with acquisition and checked by the
protected resource, which rejects anything not strictly newer than the last
token it accepted. Without that check a holder paused past its TTL resumes and
writes after the next holder already wrote — no Redis-side design prevents it,
Redlock included. Equivalently and usually better: enforce mutual exclusion where
the data lives (unique constraint, UPDATE … WHERE version = ?,
SELECT … FOR UPDATE) and treat Redis as an efficiency optimization. A design
whose only mutual-exclusion mechanism is a Redis lock is UNSAFE in Gate 3.
N/A only when no lock exists and nothing outside Redis needs mutual exclusion;
a lock nobody classified is FAIL, not N/A.
H4 — Cache observability configured. Hit rate, miss rate, eviction rate, latency, big-key and hot-key detection. Without a hit-rate metric the cache cannot be shown to work, and a silent populate failure is indistinguishable from a cold cache.
H5 — Warmup strategy for cold start and deploy. Lazy (the first request pays), eager (batch pre-populate on deploy), or gradual (canary a rising traffic share); state the first-minute DB load it implies and confirm it is survivable.
Quick decision guide — for full patterns load references/cache-patterns.md.
| Scenario | Recommended Pattern | Why |
|---|---|---|
| Read-heavy, moderate staleness OK | Cache-Aside | Simplest; app controls both read and invalidation |
| Read-your-writes on the write path | Write-Through | Cache updated synchronously on the same request — not strong consistency, and not fresh at all when the cache write fails (C3) |
| Write-heavy, async durability acceptable | Write-Behind | Defers DB writes; highest throughput but data loss risk |
| Hot key with concurrent updates | Dual-Write Debounce | Absorbs race windows via delayed second invalidation — the second delete must be durable, not an in-process sleep |
The thirteen anti-examples, with the wrong/right code for each, live in
references/cache-anti-examples.md — load it for any review or troubleshoot
request. This index exists so you can recognise a case without loading the file;
it is not a substitute for reading the pair before writing a finding.
| # | Pattern on sight | The defect | Item |
|---|---|---|---|
| AE-1 | rdb.Set(..., 0) | Immortal key: a missed invalidation is stale forever | C8 |
| AE-2 | go func() { db.Save(v) }() | Write-behind with no durable queue — the goroutine dies with the process | C6 |
| AE-3 | redis.Nil → DB query, no dedup | Stampede: every concurrent miss queries the DB | S2 |
| AE-4 | rdb.Keys(ctx, "user:*") | KEYS blocks the server for the whole scan | C2 |
| AE-5 | SetNX with no TTL, bare Del, or a discarded ok | Lock that deadlocks, releases someone else's, or never acquired | S7 |
| AE-6 | "user sees old profile" filed as a logic bug | Staleness misdiagnosed, so invalidation is never examined | C2 |
| AE-7 | Cache key omitting query parameters | One key serves several different queries | H1 |
| AE-8 | Redis as the only store | No DB backing: a restart is data loss | C1 |
| AE-9 | Async Set then immediate Get | Read-after-write race in cache population | C3 |
| AE-10 | maxmemory 0 / noeviction | Unbounded growth, or every write fails once full | H3 |
| AE-11 | PII with a 24h TTL in a shared instance | Sensitive data outliving its purpose, readable cross-service | C7 |
| AE-12 | SCAN + DEL loop in the hot path | Unpredictable invalidation latency | C2 |
| AE-13 | Load test with a cold or bypassed cache | Capacity numbers that do not describe production | H4 |
A lock that is TTL + token + CAS is well-formed, not safe (AE-5 stops at
well-formed). If it guards anything outside Redis, see C9 and
references/distributed-locks.md.
The items scored are §5's, by ID. §8 introduces none of its own — that duplication is how a Critical finding ends up graded as optional.
| Tier | Items | To pass the tier |
|---|---|---|
| Critical | C1–C9 | every scoreable item PASS. WARN fails the tier too |
| Standard | S1–S7 | ≥ 80% of scoreable items PASS (round up) |
| Hygiene | H1–H5 | ≥ 75% of scoreable items PASS (round up) |
Dynamic denominator. N/A and NOT SCOREABLE items leave both sides of the
fraction; a fixed /21 would force either a false FAIL for a system that needs
no lock, or a fake pass. A tier whose denominator reaches 0 is reported — and
cannot count as passed.
Verdict:
Every item gets a row, | ID | Verdict | Evidence or reason |, before the
summary — an item with no row is a FAIL you did not write down. Then emit the
arithmetic, never the bare verdict:
Critical p/n · Standard p/n · Hygiene p/n
N/A <ids + the structural reason>
NOT SCOREABLE <ids + the missing context>
Verdict: PASS | FAIL | INCOMPLETE
Every cache strategy review MUST produce these sections. Write "N/A — [reason]" if inapplicable.
### 9.1 Context Gate | Item | Value | Source |
### 9.2 Depth & Mode [Lite/Standard/Deep] × [review/design/troubleshoot] — rationale
### 9.3 Risk Assessment | Component | Pattern | Risk | Notes |
### 9.4 Strategy Design pattern + justification; consistency model + staleness SLA; failure-mode defenses ("N/A — Lite" at Lite depth)
### 9.5 Implementation key schema, TTL config, code patterns
### 9.6 Validation Plan hit-rate target; staleness measurement; failure injection (Redis down, hot key, mass expiry)
### 9.7 Degradation Plan what the service does while the cache is gone
### 9.8 Monitoring & Alerts hit rate, latency, eviction rate, big-key and hot-key detection
### 9.9 Uncovered Risks (MANDATORY — never empty) | Area | Reason | Impact | Follow-up |
Volume rules: FAIL findings fully detailed with a fix; WARN up to 10, then overflow to §9.9; PASS summarised. §9.9 records every assumption you used.
Scorecard summary (append after §9.9, in the §8 format):
Critical p/n · Standard p/n · Hygiene p/n
N/A <ids + reason>
NOT SCOREABLE <ids + missing context>
Verdict: PASS | FAIL | INCOMPLETE
Data basis: [full context | degraded | minimal | planning]
| Condition | Load |
|---|---|
| Standard or Deep depth | references/cache-patterns.md |
| Deep depth, or stampede/penetration/avalanche signals | references/cache-failure-modes.md |
| Any Redis lock in scope (always, not only at Deep) | references/distributed-locks.md |
| Gate 2 mode is review or troubleshoot (any depth) | references/cache-anti-examples.md |
| A conclusion on the Gate 1 version-gated list, at any depth | references/redis-version-matrix.md |
Frequently asked questions
Redis caching strategy designer and reviewer. Use even for "just add a cache" requests — cache invalidation is one of the two hard problems in computer science, and a naive implementation crea
The source record exposes this install command: npx skills add https://github.com/johnqtcg/awesome-skills --skill "skills/redis-cache-strategy". Inspect the command and pinned source before running it.
Alternatives
oaustegard/claude-skills
Generate hierarchical _FEATURES.md files that describe what a codebase DOES from a user/consumer perspective, anchored to source symbols via tree-sitting. Supports large complex codebases through feature-driven decomposition into sub-feature files. Uses a multi-pass synthesis: orientation → detail → overview rewrite. Use when someone says "what does this do", "document features", "feature inventory", "_FEATURES.md", or needs to understand a codebase's purpose before modifying it. Complements tre
HKUDS/Vibe-Trading
Create, modify, and optimize quantitative trading strategies, then backtest and evaluate them.
vasilyu1983/AI-Agents-public
Guides iOS testing with XCTest, XCUITest, Swift Testing, simctl, and xcresult. Use when choosing destinations, controlling flakes, or parsing test artifacts for native apps.
brucesongs/kali-claw
Insecure Design (OWASP A06:2025) focuses on security flaws in system architecture and design phases, rather than code implementation-level bugs.