redis_brpopBlocking right-pop — holds the connection open until data is available or timeout expires
BRPOP is the right-side variant of BLPOP. It removes and returns the last element from one or more lists, blocking if the list is empty. The blocking behaviour is identical to BLPOP — connections are held open until data arrives or the timeout fires. The choice between BLPOP and BRPOP is about queue ordering (FIFO vs LIFO), not performance; both carry the same connection-exhaustion risk.
Common Causes
- —LIFO task queues without a timeout configured
- —Shared connection pool used for blocking consumers
- —Consumers that block indefinitely during low-traffic periods
- —Stack-based processing patterns without connection isolation
How to Fix
- 1.Always specify a finite timeout in the BRPOP call
- 2.Use a dedicated Redis connection for each blocking consumer
- 3.Prefer BullMQ or similar for production task queues
- 4.Consider RPOP with a polling loop if connection isolation is not feasible
Same risk profile as BLPOP
BRPOP has identical connection-blocking behaviour to BLPOP. All the same rules apply: always use a timeout, always use a dedicated connection pool for workers.
Example
typescript
// BAD — blocks indefinitely, holds a pooled connection
const result = await redis.brpop('priority:queue', 0);
// GOOD — bounded timeout on a dedicated connection
const consumerRedis = new Redis({
host: process.env.REDIS_HOST,
maxRetriesPerRequest: null,
});
async function priorityWorker() {
while (true) {
// BRPOP processes newest-first (LIFO) — useful for priority stacks
const result = await consumerRedis.brpop('priority:queue', 5);
if (!result) continue;
const [_list, raw] = result;
const job = JSON.parse(raw);
await processJob(job);
}
}
// LIFO vs FIFO — when to use which
// BLPOP (left pop) — FIFO, tasks processed in arrival order
// BRPOP (right pop) — LIFO, most recent task processed first
// LPUSH + BLPOP = classic FIFO queue
// LPUSH + BRPOP = stack (newest first)Graceful shutdown
typescript
let running = true;
async function workerLoop(redis: Redis) {
while (running) {
const result = await redis.brpop('jobs', 2); // short timeout enables clean exit
if (!result) continue;
await processJob(JSON.parse(result[1]));
}
await redis.quit();
}
process.on('SIGTERM', () => { running = false; });