Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

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

Sponsored

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 MULTI and either DISCARD or EXEC.
  • While inside a transaction, every command queues but does not execute. The server replies with QUEUED (not the actual result).
  • DISCARD immediately exits the transaction context, discarding all queued commands.

Blockquote pro tip: DISCARD does not return a status about individual queued commands—it simply flushes the entire queue. The command itself always replies with OK.

How it works step by step

  1. Start the transaction: Send MULTI. Redis switches into transaction mode.
  2. Queue commands: Issue one or more commands (e.g., SET, INCR, LPUSH). Each returns QUEUED.
  3. Decide to abort: When you detect a problem (or simply decide not to proceed), send DISCARD.
  4. Redis reacts: The server discards the queue, exits transaction mode, and replies with OK.
  5. Back to normal: Subsequent commands execute immediately (not queued).

Key behavioral rules

  • DISCARD can only be called after MULTI and before EXEC.
  • If you call DISCARD outside 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, DISCARD does not reset the watch—you must explicitly UNWATCH if 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 DISCARD when you know you don’t want any of the queued operations. If you only want to stop watching keys, use UNWATCH.

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 DISCARD without first issuing MULTI — causes an error. Always start a transaction before discarding.
  • Trying to discard after EXEC — the transaction is already finished. Only discarding before EXEC works.
  • Assuming DISCARD also resets WATCH — it does not. Use UNWATCH explicitly 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

  1. Use UNWATCH when you want to release watches but keep the queued commands (and decide later to exec).
  2. 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.
  3. 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 calls reset()).

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

  • DISCARD cancels the current MULTI transaction without executing any of the queued commands.
  • You must be inside a transaction (after MULTI, before EXEC) to discard; otherwise you get an error.
  • DISCARD flushes the command queue, ends the transaction context, and does not reset WATCH.
  • Use DISCARD for 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.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.