Redis Transactions MULTI/EXEC Design Prompt
Design correct Redis transactions with MULTI/EXEC/WATCH optimistic locking and understand atomicity limits and rollback behavior.
- Target user
- Backend engineers building concurrent Redis workflows
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior backend engineer who has shipped high-concurrency Redis workloads and knows exactly what MULTI/EXEC does and does NOT guarantee.
I will provide:
- The operation I am trying to make atomic
- The keys involved and access pattern
- My current client code or command sequence
Your job:
1. **Clarify transaction semantics**: MULTI queues commands; EXEC runs them atomically as a single isolated unit. There is NO rollback — if a command fails at runtime, prior commands still applied.
2. **Distinguish error types**: syntax/queue-time errors abort the whole transaction (EXEC returns error, nothing runs); runtime errors (e.g. wrong type) execute the rest anyway.
3. **Design optimistic locking**: use WATCH on keys read before MULTI. If any watched key changes before EXEC, EXEC returns nil and the transaction is discarded — retry the whole read-modify-write loop.
4. **Show the check-and-set loop**: WATCH key -> read value -> MULTI -> queue writes -> EXEC -> if nil, UNWATCH and retry with backoff.
5. **Compare to Lua/EVAL**: for read-modify-write that must be server-side atomic without retries, a Lua script is often simpler than WATCH/MULTI.
6. **Cluster caveats**: all keys in a transaction must hash to the same slot; use hash tags {tag} to co-locate.
7. **Note pipelining vs transactions**: pipelining batches for throughput but is NOT atomic; do not confuse them.
8. **Recommend retry limits and idempotency** so a WATCH storm cannot spin forever.
Mark DESTRUCTIVE: any FLUSHALL/FLUSHDB in test setup, DEL of live keys, or CONFIG rewrite while validating.
---
Operation to make atomic: [DESCRIBE]
Keys involved: [DESCRIBE]
Current code/commands: [PASTE]
Why this prompt works
MULTI/EXEC is one of the most misunderstood Redis features. Engineers assume it behaves like a SQL transaction with rollback and locking — it does not. This prompt forces the model to state the real semantics (isolation without rollback, optimistic WATCH-based concurrency) before proposing a design, so you catch broken assumptions before they ship.
How to use it
- Describe the atomic operation you need — the read, the decision, the write.
- List every key touched and whether they share a hash slot.
- Paste your current code so the review targets real logic.
- Ask for the WATCH retry loop if you have a read-modify-write.
- Compare against a Lua alternative before committing.
Useful commands
# Optimistic check-and-set on a balance
redis-cli
WATCH account:42:balance
GET account:42:balance # read current value in the client
MULTI
DECRBY account:42:balance 100
EXEC # returns nil if balance changed since WATCH
# Abort cleanly
DISCARD # throws away queued commands
UNWATCH # clears all watches on the connection
# Inspect
INFO clients # blocked/watching connections
Example config
# WATCH/MULTI/EXEC retry loop (pseudo redis-cli sequence)
# Retry until EXEC succeeds or attempts exhausted
WATCH inventory:sku:1001
# item = GET inventory:sku:1001 (read in client)
# if item <= 0 -> UNWATCH, fail fast
MULTI
DECR inventory:sku:1001
LPUSH orders:queue "order-9987"
EXEC
# If EXEC returns (nil) another client changed inventory:sku:1001 -> loop again
# Equivalent atomic Lua (no retries needed)
EVAL "if tonumber(redis.call('GET', KEYS[1])) > 0 then \
redis.call('DECR', KEYS[1]); \
redis.call('LPUSH', KEYS[2], ARGV[1]); return 1 \
else return 0 end" 2 inventory:sku:1001 orders:queue order-9987
Common findings this catches
- Assumed rollback → partial writes on runtime error.
- No WATCH → lost-update race on read-modify-write.
- Retry storm → unbounded WATCH loop under contention.
- Cross-slot keys → transaction rejected in Cluster.
- Stale UNWATCH → watches leak across reused connections.
- Pipeline mistaken for transaction → non-atomic batch.
- Should be Lua → server-side atomicity simpler than WATCH.
When to escalate
- Financial/ledger correctness — involve data engineering and add reconciliation.
- Cross-slot atomic needs in Cluster — redesign key layout.
- Sustained high contention — move to Lua or a queue-based serialization model.
Related prompts
-
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 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.
-
Redis Pipelining and Batching Optimization Prompt
Optimize Redis throughput with pipelining and batching — cut round-trip latency, size batches safely, and avoid blocking the event loop.