redis_brpoplpushBlocking atomic pop-and-push between lists — deprecated in Redis 6.2
BRPOPLPUSH atomically removes the last element from a source list and pushes it to a destination list, blocking if the source is empty. It was commonly used for reliable queue patterns (the 'processing' list pattern). As of Redis 6.2, it is deprecated in favour of BLMOVE, which is more flexible and explicit about direction.
Common Causes
- —Reliable queue implementations written before Redis 6.2
- —Legacy worker code not updated after the Redis 6.2 deprecation
- —Copy-pasted queue patterns from older tutorials and blog posts
- —Dependencies that internally use BRPOPLPUSH
How to Fix
- 1.Migrate to BLMOVE, which provides the same semantics with explicit direction arguments
- 2.Always pass a finite timeout — never use 0 in production
- 3.Use BullMQ or a dedicated queue library that handles these patterns correctly
- 4.Audit dependencies for internal BRPOPLPUSH usage if upgrading Redis server
Deprecated since Redis 6.2
BRPOPLPUSH is still functional but no longer receives updates. New features and optimisations target BLMOVE. Migrate now to avoid compatibility issues on future Redis server versions.
Example
typescript
// BAD — deprecated command
const job = await redis.brpoplpush('queue:pending', 'queue:processing', 0);
// GOOD — migrate to BLMOVE (Redis 6.2+)
// BLMOVE source destination LEFT|RIGHT LEFT|RIGHT timeout
const job = await redis.blmove('queue:pending', 'queue:processing', 'RIGHT', 'LEFT', 5);
// The reliable queue pattern with BLMOVE
async function reliableWorker(redis: Redis) {
const PROCESSING_LIST = 'queue:processing';
const PENDING_LIST = 'queue:pending';
// On startup, recover any jobs left in processing from a previous crash
let stuck: string | null;
while ((stuck = await redis.rpoplpush(PROCESSING_LIST, PENDING_LIST)));
while (true) {
// Move from pending → processing atomically
const raw = await redis.blmove(PENDING_LIST, PROCESSING_LIST, 'RIGHT', 'LEFT', 5);
if (!raw) continue;
const job = JSON.parse(raw);
try {
await processJob(job);
await redis.lrem(PROCESSING_LIST, 1, raw); // remove on success
} catch (err) {
await redis.lrem(PROCESSING_LIST, 1, raw);
await redis.lpush('queue:failed', raw); // move to DLQ
}
}
}