When a consumer dies its pending entries belong to a name that will never acknowledge them, so something has to reassign them — and in Redis 5 that something is code you write.
// every 30 seconds, per worker
$stale = $redis->rawCommand('XPENDING', 'orders', 'workers',
'IDLE', 60000, '-', '+', 10);
foreach ($stale as $entry) {
$redis->rawCommand('XCLAIM', 'orders', 'workers', $this->name,
60000, $entry[0]);
}
The IDLE filter on XPENDING is what makes this cheap — without it you fetch everything pending and filter in PHP. Sixty seconds is a threshold to choose deliberately: too short and a slow but healthy consumer has its work stolen and done twice, which is only safe because handlers are idempotent. XAUTOCLAIM arrives in 6.2 and collapses this into one command; until then the timer is part of every worker.