Skip to content

Blocking Operations

Blocking commands that wait for data to become available, enabling queue patterns and real-time processing.

CommandSyntaxDescription
BLPOPBLPOP key [key ...] timeoutBlock until element available at list head
BRPOPBRPOP key [key ...] timeoutBlock until element available at list tail
BLMOVEBLMOVE src dst LEFT|RIGHT LEFT|RIGHT timeoutBlock until element can be moved
BRPOPLPUSHBRPOPLPUSH src dst timeoutBlock pop from src, push to dst (deprecated)
XREAD BLOCKXREAD BLOCK ms STREAMS key idBlock until new stream entries
  1. Client sends blocking command with timeout
  2. If data exists, returns immediately
  3. If no data, server waits until:
    • Data becomes available (another client pushes)
    • Timeout expires (returns nil)
    • Connection closes

Consumer (blocks waiting for work):

Terminal window
127.0.0.1:6379> BLPOP queue:jobs 30
# ... waits up to 30 seconds ...
1) "queue:jobs"
2) "job:123"

Producer (adds work):

Terminal window
127.0.0.1:6379> LPUSH queue:jobs "job:123"
(integer) 1
# Consumer immediately receives the job

Check multiple queues, return from first with data:

Terminal window
# Wait on multiple queues (priority order)
127.0.0.1:6379> BLPOP queue:high queue:medium queue:low 10
# Returns from first non-empty queue
1) "queue:high"
2) "urgent-task"
Terminal window
# FIFO queue - push left, pop right (blocking)
127.0.0.1:6379> BRPOP queue:tasks 0
# 0 = wait forever

Move element atomically between lists:

Terminal window
# Worker: take job from pending, move to processing
127.0.0.1:6379> BLMOVE jobs:pending jobs:processing LEFT RIGHT 30
"job:456"
# After job complete, remove from processing
127.0.0.1:6379> LREM jobs:processing 1 "job:456"
(integer) 1
Terminal window
# Wait for new stream entries
127.0.0.1:6379> XREAD BLOCK 5000 STREAMS events $
# Waits up to 5 seconds for new entries after current time
# When entry arrives:
1) 1) "events"
2) 1) 1) "1234567890123-0"
2) 1) "type"
2) "click"
3) "user"
4) "123"
Terminal window
# 5 second timeout
127.0.0.1:6379> BLPOP empty:queue 5
(nil) # Nothing after 5 seconds
# Immediate return if data exists
127.0.0.1:6379> LPUSH myqueue "item"
(integer) 1
127.0.0.1:6379> BLPOP myqueue 30
1) "myqueue"
2) "item" # Returns immediately, doesn't wait
Terminal window
# Wait indefinitely for work
127.0.0.1:6379> BLPOP queue:jobs 0
# Blocks until data or connection closed
Terminal window
# Producer: add jobs
LPUSH queue:jobs "job:1" "job:2" "job:3"
# Consumer: process jobs (blocking)
while true:
BLPOP queue:jobs 0 # Wait forever
# Process job...
Terminal window
# Producer: add to appropriate queue
LPUSH queue:critical "urgent-job"
LPUSH queue:normal "regular-job"
LPUSH queue:low "background-job"
# Consumer: check in priority order
BLPOP queue:critical queue:normal queue:low 10
Terminal window
# Step 1: Worker claims job
job = BLMOVE pending processing LEFT RIGHT 30
# Step 2: Process job
# ... do work ...
# Step 3a: Success - remove from processing
LREM processing 1 job
# Step 3b: Failure - move back to pending
LMOVE processing pending LEFT LEFT
Terminal window
# Subscriber (blocking receive)
while true:
message = BLPOP channel:notifications 0
# Handle message...
# Publisher (non-blocking send)
LPUSH channel:notifications '{"event":"update"}'
Terminal window
# Consumer: wait for events
127.0.0.1:6379> XREAD BLOCK 0 STREAMS events $
# $ = only new entries
# Producer: add events
127.0.0.1:6379> XADD events * type "click" page "/home"
"1234567890123-0"
Terminal window
# Create group
127.0.0.1:6379> XGROUP CREATE events mygroup $ MKSTREAM
# Consumer: blocking read from group
127.0.0.1:6379> XREADGROUP GROUP mygroup consumer-1 BLOCK 5000 STREAMS events >
Terminal window
# Wait on multiple streams
127.0.0.1:6379> XREAD BLOCK 10000 STREAMS orders:new orders:updated 0-0 0-0
  • Blocking commands tie up the connection
  • Use separate connections for blocking and regular commands
  • Set appropriate timeouts to avoid resource exhaustion
ValueBehavior
0Wait forever
NWait N seconds (BLPOP/BRPOP) or N milliseconds (XREAD)
ModeImplementationBest For
EmbeddedPolling with configurable intervalSingle-process apps
ServerAsync/await on TCP connectionsMulti-client coordination

When multiple clients wait on the same key:

  • First client to wait is first to receive
  • FIFO ordering for blocked clients
Terminal window
# Multiple workers competing for jobs
# Worker 1:
BLPOP jobs 0
# Worker 2:
BLPOP jobs 0
# Producer adds job - one worker gets it
LPUSH jobs "task:123"
Terminal window
# Token bucket pattern
# Consumer waits for tokens
BLPOP rate:tokens 1
# Background process refills tokens
LPUSH rate:tokens "token"
EXPIRE rate:tokens 1
Terminal window
# Add job with delay using sorted set + blocking list
ZADD delayed:jobs <future_timestamp> "job:123"
# Background process moves ready jobs
while true:
# Check for ready jobs
ready = ZRANGEBYSCORE delayed:jobs 0 <now> LIMIT 0 1
if ready:
ZREM delayed:jobs ready
LPUSH queue:jobs ready
sleep 100ms
# Workers process from blocking queue
BLPOP queue:jobs 0
Terminal window
# Collect events, process in batches
# Producer adds events
LPUSH events:buffer '{"event":"click"}'
# Consumer waits then processes batch
while true:
event = BLPOP events:buffer 5 # 5 second timeout
if event:
batch.append(event)
if len(batch) >= 100 or timeout:
process_batch(batch)
batch = []