You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qpid Proton Python release(delivered=True)在ActiveMQ Artemis中不触发重投计数

Apache ActiveMQ Artemis 2.40.0 + Qpid Proton Python 0.39.0:软NACK后消息无限重投,无法触发max-delivery-attempts

环境与需求

  • 消息代理:Apache ActiveMQ Artemis 2.40.0
  • AMQP客户端:Qpid Proton Python 0.39.0(python-qpid-proton)
  • 核心需求:通过客户端软NACK操作,让消息按照broker配置的max-delivery-attempts(5次)和redelivery-delay(5秒)重投,超过次数后自动进入死信队列(DLQ)

已配置的broker.xml地址规则

在broker.xml中配置全局地址规则:

<address-setting match="#">
    <expiry-address>ExpiryQueue</expiry-address>
    <dead-letter-address>DLQ</dead-letter-address>
    <auto-create-dead-letter-resources>true</auto-create-dead-letter-resources>
    <dead-letter-queue-prefix></dead-letter-queue-prefix>
    <dead-letter-queue-suffix>.DLQ</dead-letter-queue-suffix>
    <max-delivery-attempts>5</max-delivery-attempts>
    <redelivery-delay>5000</redelivery-delay>
</address-setting>

初始消费者代码

消费者尝试用release(delivered=True)实现软NACK的on_message逻辑:

def on_message(self, event):
    message = event.message
    status = send_message_callback(self.enrollment["target_url"], message.body)

    if 200 <= status < 300:
        self.accept(event.delivery)
    else:
        # Explicitly NACK the message
        self.release(event.delivery, delivered=True)

问题现象

  1. 调用release(delivered=True)后,Artemis无限重投消息,完全不统计投递次数到max-delivery-attempts配置值
  2. 使用reject(event.delivery)会直接将消息送入DLQ,不符合“先重投再进DLQ”的需求
  3. 尝试添加<persist-delivery-count-before-delivery>标签到broker.xml,但该标签破坏Artemis 2.40.0的schema,导致服务无法启动
  4. Qpid Proton的on_released、on_settled、on_rejected回调均未触发

解决方案:修正后的消费者代码

需在结算消息前手动更新本地投递状态,明确标记消息投递失败但仍可重新投递,再用MODIFIED状态完成结算。修正后的代码如下:

def on_message(self, event):
    message = event.message
    status = send_message_callback(self.enrollment["target_url"], message.body)

    if 200 <= status < 300:
        self.accept(event.delivery)
    else:
        # Explicitly NACK the message with proper state update
        local_state = event.delivery.local
        local_state.failed = True
        local_state.undeliverable = False
        event.delivery.update(local_state.type)
        self.settle(event.delivery, event.delivery.MODIFIED)

逻辑说明

  • failed=True:告知broker本次投递失败,需要递增投递次数
  • undeliverable=False:告知broker消息仍可再次投递,不会直接进入DLQ
  • 用MODIFIED状态结算后,Artemis会正确遵循配置的重投延迟和最大投递次数限制,超过次数后自动将消息转入DLQ

内容的提问来源于stack exchange,提问作者Daniel Nascimento

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:40:20