amqpmessage::getredelivered()仅标识消息是否被rabbitmq重投递,不反映业务重试次数;真实重试次数需从x-death header的count字段获取,业务重试数=count-1,且须用end()取最后一条记录。

AMQPMessage::getRedelivered() 返回的是连接级重投,不是业务重试次数
很多人以为 getRedelivered() 能拿到“这是第几次重试”,其实它只表示这条消息是否被 RabbitMQ 重新投递过——即消费者连接断开后消息被自动发回(redelivered=true),或手动 nack(requeue=true) 后立刻又取到。它不记录次数,也不区分是第 1 次还是第 5 次重试。RabbitMQ 协议本身不维护重试计数器。
真正能用的重试次数必须从 x-death header 里读取
RabbitMQ 在每次消息被拒绝并进入死信流程时,会在 header 中追加 x-death 字段,里面包含一个数组,每重试一次就 push 一条记录,其中 count 就是当前累计投递次数(含首次)。注意:这个值是“总投递次数”,所以业务重试次数 = count - 1。
-
$headers = $msg->get('application_headers');取出 headers if (isset($headers['x-death']) && is_array($headers['x-death'])) { $death = end($headers['x-death']); $retryCount = $death['count'] - 1; }- 必须用
end()取最后一条,因为多次死信会追加多条,最新那次在末尾 - 若消息从未进过死信流程(比如刚发来第一次消费),
x-death不存在,$retryCount应视为 0
别依赖 message_id 或自定义 retry 字段做幂等判断
生产者设的 retry 字段(如 application_headers => new AMQPTable(['retry'=>0]))在重试过程中不会自动更新——除非你每次 nack 前手动改写再 publish,但这会丢失原始 delivery_tag 和 redelivered 状态,且极易因并发导致计数错乱。更严重的是:message_id 是生产者可控字段,不可信;而 Redis SETNX 幂等校验必须基于业务主键(如 md5("order_123456")),不能基于任何消息元数据。
Horizon / laravel-queue-rabbitmq 用户要额外检查 delivery_limit 是否生效
如果你用的是 Laravel 生态,x-delivery-limit 必须在队列声明时显式传入(如 ['x-delivery-limit' => 5]),否则 x-death 里的 count 永远最多为 1。还要确认:config/rabbitmq.php 中的 retry_after 与 Horizon 的 tries 配置一致,否则框架层和 RabbitMQ 层对“失败”的判定节奏不同步,x-death 不会按预期累积。
最容易被忽略的是:x-death 是 array 类型,但 PHP AMQP 扩展有时会把它反序列化成 stdClass 对象,读取前务必 is_array() 或 (array) 强转,否则 end() 失效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











