Redis Lua Scripting Review Prompt
Review Redis Lua scripts — EVAL/EVALSHA, atomicity, KEYS vs ARGV, and script safety — to keep server-side logic correct and non-blocking.
- Target user
- Engineers writing Redis Lua scripts
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT
The prompt
You are a senior SRE and Redis expert who reviews server-side Lua scripts for correctness and safety. I will provide: - The Lua script and how it's invoked - The keys and arguments passed - The atomicity/consistency goal Your job: 1. **Atomicity model**: a script runs atomically — the server executes it as one unit, blocking all other commands until it returns. So keep scripts FAST; a long loop stalls the entire instance. 2. **KEYS vs ARGV**: every key the script touches must be passed via `KEYS[]` (not hardcoded), so Cluster can route correctly and behavior is predictable. Non-key data goes in `ARGV[]`. Accessing keys not declared in `KEYS` is unsafe in Cluster. 3. **Cluster slot rule**: all `KEYS` must hash to the same slot (use hash tags) or you get `CROSSSLOT`. 4. **EVAL vs EVALSHA**: `SCRIPT LOAD` returns a SHA; call `EVALSHA <sha> numkeys ...` to avoid resending the body. Handle `NOSCRIPT` by falling back to `EVAL` (e.g. after a restart/failover flushed the script cache). 5. **Determinism**: replicated/persisted effects must be deterministic. Avoid non-deterministic sources (random, time) unless using `redis.call` on Redis-provided randomness carefully; effects replication (default in modern Redis) mitigates this but review it. 6. **Error handling**: `redis.call` raises and aborts; `redis.pcall` returns the error for you to handle. A script error mid-way does NOT roll back already-applied writes — Redis has no script rollback. 7. **Return types**: understand Lua↔Redis type conversion (nil → false, numbers truncated to integers, tables → arrays). 8. **Alternatives**: for reusable logic consider Functions (`FUNCTION LOAD`); for simple atomicity a `MULTI/EXEC` transaction may suffice. Mark DESTRUCTIVE: long/looping scripts blocking the server, `SCRIPT KILL` needed on a stuck script (only works if it hasn't written), scripts calling `FLUSHALL`/`DEL` broadly, and `KEYS`/`DEBUG` inside scripts on prod. --- Script: [PASTE] Keys/args: [DESCRIBE] Atomicity goal: [DESCRIBE]
Why this prompt works
Lua scripts are Redis’s atomicity tool, but atomic means the whole server is blocked while they run — and there is no rollback on error. This prompt reviews the two things that most often go wrong: long-running logic that stalls the instance, and hardcoded keys that break Cluster routing. It enforces the KEYS/ARGV discipline and the EVALSHA/NOSCRIPT fallback that production scripts need.
How to use it
- Paste the script and its invocation including
numkeys. - List every key it reads or writes — they must all be in
KEYS[]. - State the atomic outcome you want so correctness can be judged.
- Note if you run Cluster — then all keys need one slot via hash tags.
Useful commands
# Load once, call by SHA
SHA=$(redis-cli SCRIPT LOAD "return redis.call('INCR', KEYS[1])")
redis-cli EVALSHA "$SHA" 1 counter:page
# Direct EVAL (body sent each time)
redis-cli EVAL "if redis.call('GET',KEYS[1])==ARGV[1] then return redis.call('DEL',KEYS[1]) else return 0 end" 1 lock:job token123
# Script cache management
redis-cli SCRIPT EXISTS "$SHA"
redis-cli SCRIPT LOAD "return 1"
redis-cli SCRIPT FLUSH ASYNC
# Stuck-script recovery (only before it writes)
redis-cli SCRIPT KILL
# Latency check while scripts run
redis-cli --latency
Example config
-- Atomic compare-and-delete lock release (Redlock-style)
-- KEYS[1] = lock key, ARGV[1] = owner token
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
else
return 0
end
-- Atomic token-bucket-ish rate limit
-- KEYS[1] = counter, ARGV[1] = limit, ARGV[2] = window(sec)
local current = redis.call('INCR', KEYS[1])
if current == 1 then
redis.call('EXPIRE', KEYS[1], tonumber(ARGV[2]))
end
if current > tonumber(ARGV[1]) then
return 0 -- rejected
end
return 1 -- allowed
Common findings this catches
- Long/looping script → blocks the whole server; move work out.
- Hardcoded keys → breaks Cluster routing and slot safety.
- Undeclared
KEYS→CROSSSLOTor wrong-node access in Cluster. - No
NOSCRIPTfallback → EVALSHA fails after cache flush/failover. - Assumed rollback → partial writes persist after mid-script error.
- Non-determinism → replica/AOF divergence.
When to escalate
- Scripts complex enough to warrant Redis Functions or app-side logic.
- Scripts whose latency shows up in
--latency— redesign for smaller units. - Cross-slot atomic needs in Cluster — rethink key layout.
Related prompts
-
Redis Cluster Sharding Design Prompt
Design Redis Cluster sharding — 16384 hash slots, resharding, hash tags, and multi-key operation constraints across shards.
-
Redis Distributed Lock and Redlock Design Prompt
Design SET NX PX distributed locks safely, evaluate Redlock and its controversy, and add fencing tokens to avoid split-brain writes.
-
Redis Rate Limiter Design Prompt
Design token bucket and sliding window rate limiters in Redis using INCR/EXPIRE or atomic Lua, avoiding race conditions and TTL bugs.
-
Redis Transactions MULTI/EXEC Design Prompt
Design correct Redis transactions with MULTI/EXEC/WATCH optimistic locking and understand atomicity limits and rollback behavior.