DISCARD in Redis
Learn how to discard Redis transactions using the DISCARD command with a step-by-step walkthrough, edge cases, and practical exercises.
Focus: discard redis transactions
You have a pipeline of Redis commands bundled inside MULTI… but suddenly you realize the logic is wrong or you’re about to write bad data. Without an escape hatch, you’d be forced to execute the faulty transaction and then clean up the mess. That’s exactly the pain DISCARD solves: it’s your undo button for an in‑flight Redis transaction.
The problem this lesson solves
When you issue MULTI, Redis queues every subsequent command without executing them until EXEC is called. This is powerful for batching atomic operations, but it also means a mistake—like hitting the wrong key, queuing an incompatible type, or wanting to abort due to application logic—will commit garbage unless you have a way to cancel. Waiting for EXEC to fail partway through can leave your data in an inconsistent state. DISCARD gives you the ability to discard the entire queued transaction cleanly, returning your connection to normal mode without applying any changes.
Core concept / mental model
Think of MULTI as starting a “journal” page. Every command you write after MULTI is a line on that page. EXEC says “publish the whole page” to your dataset. DISCARD says “tear out the page and throw it away”—no commands get executed, the transaction is aborted, and the queue is emptied.
- The transaction context is the period between
MULTIand eitherDISCARDorEXEC. - While inside a transaction, every command queues but does not execute. The server replies with
QUEUED(not the actual result). DISCARDimmediately exits the transaction context, discarding all queued commands.
Blockquote pro tip:
DISCARDdoes not return a status about individual queued commands—it simply flushes the entire queue. The command itself always replies withOK.
How it works step by step
- Start the transaction: Send
MULTI.Redis switches into transaction mode. - Queue commands: Issue one or more commands (e.g.,
SET,INCR,LPUSH). Each returnsQUEUED. - Decide to abort: When you detect a problem (or simply decide not to proceed), send
DISCARD. - Redis reacts: The server discards the queue, exits transaction mode, and replies with
OK. - Back to normal: Subsequent commands execute immediately (not queued).
Key behavioral rules
DISCARDcan only be called afterMULTIand beforeEXEC.- If you call
DISCARDoutside a transaction, Redis returns an error:ERR DISCARD without MULTI. - Discarding a transaction releases any keys that were being watched by
WATCH(if used). However,DISCARDdoes not reset the watch—you must explicitlyUNWATCHif you want to reuse a watched key later.
Hands-on walkthrough
Let’s simulate a scenario where you start a transaction, queue some commands, then decide to cancel.
Example 1: Basic discard
# Connect to Redis CLI
redis-cli
# Step 1: Start transaction
MULTI
# Output: OK
# Step 2: Queue two SET commands
SET mykey1 "hello"
# Output: QUEUED
SET mykey2 "world"
# Output: QUEUED
# Step 3: Abort the transaction
DISCARD
# Output: OK
# Step 4: Verify nothing was written
GET mykey1
# Output: (nil)
Example 2: Discard in Python (with redis-py)
import redis
r = redis.Redis(decode_responses=True)
# Start transaction
pipe = r.pipeline(transaction=True)
pipe.multi()
pipe.set("user:10:name", "Alice")
pipe.incr("user:10:visits")
# Oops! Wrong user? Discard.
pipe.discard()
# Confirm no keys were created
print(r.exists("user:10:name")) # 0 (false)
print(r.exists("user:10:visits")) # 0 (false)
Example 3: Conditional discard based on data
import redis
r = redis.Redis(decode_responses=True)
# We only want to SET if a specific condition holds (simulate)
should_proceed = False # Imagine this comes from external logic
pipe = r.pipeline()
pipe.multi()
pipe.set("config:mode", "dark")
pipe.set("config:timeout", "60")
if not should_proceed:
pipe.discard()
print("Transaction discarded due to condition")
else:
pipe.execute()
print("Transaction executed")
Expected output (no keys written):
Transaction discarded due to condition
Compare options / when to choose what
| Option | When to use | Side effects |
|---|---|---|
DISCARD |
You want to cancel the entire queued batch without executing anything | Queued commands discarded; transaction context ended; WATCH not reset (but keys unwatched). |
EXEC |
You want to commit the batch atomically | All commands run; any error aborts remaining commands (but executed ones remain). |
UNWATCH |
You used WATCH and want to release the watched keys without cancelling the transaction |
Does not discard queued commands. You must still EXEC or DISCARD manually. |
| Kill connection | Drastic: close the client socket | Transaction is automatically discarded by Redis when connection drops. Heavy-handed. |
Choose
DISCARDwhen you know you don’t want any of the queued operations. If you only want to stop watching keys, useUNWATCH.
Troubleshooting & edge cases
Common mistake 1: Calling DISCARD without MULTI
redis-cli DISCARD
# (error) ERR DISCARD without MULTI
Fix: Ensure you have a prior MULTI on the same connection. Use MULTI first.
Common mistake 2: Attempting to discard after EXEC
MULTI
SET x 1
EXEC
# OK
DISCARD
# (error) ERR DISCARD without MULTI
Fix: EXEC ends the transaction, so DISCARD becomes invalid. Only discard before calling EXEC.
Common mistake 3: Forgetting that WATCH is not reset by DISCARD
WATCH mykey
MULTI
SET mykey 999
DISCARD
# WATCH is still active on mykey!
Fix: If you plan to retry the transaction later, explicitly UNWATCH to avoid stale watches causing unexpected failures.
Edge case: Network timeout during transaction
If the connection drops while commands are queued, Redis automatically discards the transaction—no action needed. This is safe, but you lose the commands.
What you learned & what's next
You now understand:
- How DISCARD cancels a Redis transaction in progress.
- The precise step: MULTI → queue commands → DISCARD → queue cleared.
- How to use it in a Python client to conditionally abort.
- The difference between DISCARD, EXEC, and UNWATCH.
Next: Learn how to watch keys for optimistic locking with WATCH. This lets you detect changes during a transaction and retry or discard based on changing data—a critical pattern for building reliable counters and reservation systems.
Practice by writing a small script that starts a transaction, reads a key (not inside the transaction), decides based on its value whether to discard or execute, and verifies no keys were changed after discard.
Practice recap
Write a Python script that uses redis.Redis to start a transaction, queue two SET commands, then discard based on a random condition (e.g., random.choice([True, False])). Verify that no keys were written by checking exists(). Then extend it to simulate a bank transfer: start MULTI, queue DECR and INCR, and discard if the balance would go negative.
Common mistakes
- Calling
DISCARDwithout first issuingMULTI— causes an error. Always start a transaction before discarding. - Trying to discard after
EXEC— the transaction is already finished. Only discarding beforeEXECworks. - Assuming
DISCARDalso resetsWATCH— it does not. UseUNWATCHexplicitly if you need to clear watches. - Forgetting that queued commands are not validated until
EXEC— so a syntax error might not surface until after you’ve discarded. This is expected, not a bug.
Variations
- Use
UNWATCHwhen you want to release watches but keep the queued commands (and decide later to exec). - Close the client connection to force Redis to discard the transaction — especially useful in error handling when you’re connecting from a short‑lived script.
- In python, you can also simply not call
execute()on the pipeline object — the transaction is never committed, but it remains open until the pipeline context manager exits (which callsreset()).
Real-world use cases
- E‑commerce checkout: If inventory check fails during a multi‑key reservation, immediately discard the transaction to avoid holding stock.
- User profile update: When a profile change requires multiple SETs and a validation step before commit, discard if the input is invalid.
- Caching warm‑up: A background job queues many SETs in a transaction but discards if the upstream data source returns an error mid‑batch.
Key takeaways
DISCARDcancels the currentMULTItransaction without executing any of the queued commands.- You must be inside a transaction (after
MULTI, beforeEXEC) to discard; otherwise you get an error. DISCARDflushes the command queue, ends the transaction context, and does not resetWATCH.- Use
DISCARDfor conditional abort: check runtime conditions and decide to keep or discard the batch. - In python errors, discarding is safer than letting an incomplete transaction hang, even if you later close the connection.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.