node.js中rabbitmq手动ack需显式设置noack:false,业务完成调ack,失败用nack并控制requeue;防死循环需加重试计数或转死信队列;断连时unack消息自动恢复为ready。

Node.js 使用 RabbitMQ 时,手动 ACK 和错误消息重回队列不是默认行为,必须显式配置消费者端的确认模式,并在业务逻辑中主动调用 ack 或 nack。关键在于:不签收 ≠ 自动重试,而是由你控制何时成功、何时失败、失败后是否重投。
开启手动ACK模式
连接创建后,消费时需将 noAck 设为 false,否则 RabbitMQ 会立即删除消息,不管后续是否处理成功:
- 使用
channel.consume(queueName, callback, { noAck: false }) - 若用
amqplib的assertQueue+consume组合,必须显式传入该选项 - Spring Boot 等框架对应配置是
spring.rabbitmq.listener.simple.acknowledge-mode=manual,但 Node.js 中没有自动配置,全靠代码控制
正确实现手动ACK与NACK
每次收到消息,都要在回调中明确调用 ack 或 nack,不能遗漏或依赖 try/catch 自动处理:
诊断并恢复通过 SSH 隧道连接的 OpenClaw 节点。用于解决配对必需错误、隧道冲突、远程端点错误以及 SSH 目标配置错误等问题。
-
channel.ack(msg):仅当业务逻辑完全执行完毕(如数据库写入成功、第三方调用返回 OK)才调用,表示消息已可靠处理 -
channel.nack(msg, false, true):第三个参数requeue=true表示失败后重新入队,供其他消费者或本消费者下次再取 - 避免在 catch 块外调用 nack,也别在未捕获异常时直接退出回调——这会导致连接断开后消息滞留为 unack 状态,无法被其他消费者获取
防止重回队列死循环
如果消息因业务逻辑缺陷(如固定字段缺失、接口永远超时)持续失败,nack(..., true) 会不断把它塞回队头,造成无限重试:
- 加简单重试计数:把重试次数存入消息 header(如
msg.properties.headers['retry-count'] = (count || 0) + 1),超过阈值(如 3 次)则nack(..., false, false)拒绝并丢弃,或转发到死信队列 - 不要用
requeue=true处理不可恢复错误(如 JSON 解析失败、必填字段为空),这类应直接nack(..., false, false)并记录告警 - 测试时可用管控台命令
rabbitmqctl list_queues name messages_ready messages_unacknowledged观察队列积压和 unack 数量,验证是否按预期流转
补充:连接中断时的消息状态
消费者进程崩溃或网络断开时,只要没调用 ack,RabbitMQ 会自动把 unack 消息转为 ready 状态(前提是 channel 关闭前未设置 recovery 且 broker 未配置 consumer_cancel_notify):
- 这意味着其他在线消费者能立刻拿到该消息,无需额外代码干预
- 但要注意:若消费者长时间卡住(如死循环、GC 停顿),消息会一直卡在 unack,影响吞吐,此时需结合
prefetch限流(如channel.prefetch(1))避免单个消费者堆积过多未确认消息










