A retry limit lives in the consumer and resets when the consumer restarts, so a message that crashes the process is retried forever.
// the count belongs on the MESSAGE, not in the worker
if ($message->deliveryCount() >= 5) {
$this->deadLetter($message, 'delivery count exceeded');
return;
}
// Redis streams: XPENDING reports the delivery count
// SQS: ApproximateReceiveCount
// RabbitMQ: an x-death header, after a dead-letter round trip
A message that kills the worker never reaches the handler’s retry logic, which is exactly the message that most needs limiting. Every broker exposes a delivery count in a slightly different way and none of them make it prominent, which is why this is usually discovered by finding a queue that has been retrying the same message for a week.