Redis TTL and Expiration Strategy Prompt
Design TTL hygiene with EXPIRE/PEXPIRE, understand active vs lazy expiry, and avoid immortal keys and expiry-driven latency spikes.
- Target user
- Engineers managing key lifecycles and memory
- Difficulty
- Beginner
- Tools
- Claude, ChatGPT
The prompt
You are a senior Redis engineer who has debugged memory leaks and latency spikes caused by TTL mishandling. I will provide: - What keys I create and their intended lifetime - How I set expiry today - Any symptoms (growing memory, latency, keys that never die) Your job: 1. **Set TTLs atomically at write**: prefer `SET key val EX <s>` / `PX <ms>` or `GETEX`, not SET followed by a separate EXPIRE — a crash between them leaves an immortal key. 2. **Know the commands**: EXPIRE (seconds), PEXPIRE (ms), EXPIREAT/PEXPIREAT (absolute unix time), TTL/PTTL to inspect, PERSIST to remove a TTL. Note EXPIRE options NX/XX/GT/LT (set only if none/exists/greater/lower) in Redis 7+. 3. **Explain how expiry works**: keys expire via lazy expiry (removed when next accessed) AND a background active-expiry cycle that samples volatile keys ~10x/sec. A key with a TTL that is never accessed still gets collected by the active cycle, but not instantly. 4. **Watch the write-on-expire trap**: writing to a key does NOT clear its TTL, but some commands do — SET replaces the key and DROPS its TTL unless you re-apply KEEPTTL. Document which of your commands reset TTL. 5. **Prevent immortal keys**: audit with a scan for keys where TTL == -1 that should be volatile. 6. **Manage latency**: mass simultaneous expiry (e.g. all keys with the same EXPIREAT) can spike CPU during the active cycle — jitter TTLs. 7. **TTL + eviction interplay**: volatile-* eviction policies only evict keys that have a TTL — TTL hygiene is what makes those policies work. 8. **Hygiene checks**: sample TTL distribution, alert on unbounded key growth. Mark DESTRUCTIVE: PERSIST on keys that should expire (memory leak), CONFIG changes to maxmemory-policy, FLUSHDB to "reset" TTLs. --- Keys and lifetimes: [DESCRIBE] How you set expiry: [DESCRIBE] Symptoms: [DESCRIBE]
Why this prompt works
TTL bugs are invisible until memory climbs or latency spikes. The two worst offenders — SET silently dropping a TTL, and non-atomic SET+EXPIRE creating immortal keys — pass code review easily. This prompt makes the model reason about active vs lazy expiry and audit for keys that should have a TTL but do not.
How to use it
- List each key family and its intended lifetime.
- Show how you set expiry — atomic or two-step.
- Describe symptoms like creeping memory or periodic latency.
- Ask for an audit query to find immortal keys.
Useful commands
# Set TTL atomically at write time
redis-cli SET cache:page:home "<html>" EX 300
redis-cli SET cache:page:home "<html>" KEEPTTL # update value, keep TTL
# Inspect and adjust
redis-cli TTL cache:page:home # seconds left; -1 = no TTL, -2 = missing
redis-cli PTTL cache:page:home # milliseconds
redis-cli EXPIRE cache:page:home 600 GT # extend only if new TTL is greater (7+)
redis-cli PERSIST cache:page:home # remove TTL (use with care)
redis-cli EXPIREAT cache:page:home 1780000000 # absolute unix expiry
# Audit: find keys with no TTL that should have one (non-blocking scan)
redis-cli --scan --pattern 'cache:*' | while read k; do \
[ "$(redis-cli TTL "$k")" = "-1" ] && echo "IMMORTAL: $k"; done
Example config
# redis.conf tuning around expiration
maxmemory 8gb
maxmemory-policy volatile-lru # only works because keys carry TTLs
# Active-expire effort (higher = more aggressive collection, more CPU)
# Default is fine; raise only if lazy expiry lags memory:
# active-expire-effort 1 # 1 (default) .. 10
# Application rule: jitter TTLs to avoid synchronized expiry storms
# EXPIRE cache:<id> $((3600 + RANDOM % 300))
Common findings this catches
- SET drops TTL → immortal key, memory leak.
- Non-atomic SET+EXPIRE → key with no TTL on crash.
- Expiry storm → synchronized EXPIREAT latency spike.
- Stray PERSIST → cache key turned permanent.
- Missing TTLs → volatile-* eviction cannot free memory.
- Memory lags TTL → passive keys awaiting active cycle.
- No TTL audit → unbounded key growth unnoticed.
When to escalate
- Persistent memory growth despite TTLs — capacity and key-design review.
- Recurring expiry-cycle latency — tune active-expire-effort with SRE.
- TTLs coupled to correctness (locks, limiters) — cross-check those designs.
Related prompts
-
Redis Eviction Policy Tuning Prompt
Tune Redis maxmemory and maxmemory-policy — allkeys-lru, volatile-ttl, LFU, noeviction — to match cache vs data-store workloads.
-
Redis Keyspace Notifications Setup Prompt
Configure notify-keyspace-events to receive expired, evicted, and mutation events via keyspace/keyevent pub/sub, with delivery caveats.
-
Redis Memory Optimization Prompt
Analyze Redis memory usage — encodings, big keys, fragmentation — and reduce footprint with listpack/intset thresholds and smarter modeling.