I'm using Apache ActiveMQ Artemis 2.40.0 as the broker and Qpid Proton Python 0.39.0 (python-qpid-proton
) as the AMQP 1.0 client.
The goal is to have messages redelivered up to a configured limit (max-delivery-attempts
) when the consumer explicitly does not acknowledge (NACK) a message, using the release(delivered=True)
method from Proton's MessagingHandler
.
I’ve configured the broker.xml
in Artemis with the following <address-setting>
block:
<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>
Here’s a snippet from the on_message
method in my Qpid Proton consumer:
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)
Despite using release(delivered=True)
, Artemis seems to redeliver the message indefinitely (ignoring the <max-delivery-attempts>
), unless I switch to reject(event.delivery)
, which immediately sends the message to the DLQ on the first failure.
I’ve also tried adding the tag <persist-delivery-count-before-delivery>true</persist-delivery-count-before-delivery>
to the broker.xml
, but without success.
Upon release(delivered=True)
, Artemis should:
max-delivery-attempts
and redelivery-delay
release(delivered=True)
should behave as a soft NACK, as described in Proton’s documentation
Artemis keeps redelivering the message infinitely, never counting toward max-delivery-attempts
. It seems the delivery count is not being persisted or acknowledged as expected from Proton.
release(delivery, delivered=True)
reject()
(works, but not the behavior I want)<persist-delivery-count-before-delivery>
to broker config (breaks schema in Artemis 2.40.0)on_released
, on_settled
, on_rejected
are not triggered on release(delivered=True)
release(delivered=True)
supported by Artemis 2.40.0 as a way to increment delivery count?Thanks in advance!
I wasn't updating the local state object before releasing the message. So in order to use the max-delivery-attempts
policy with the DLQ
defined in broker.xml, it must complete these local properties:
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
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)
I think this is arguably a bug in the Qpid Proton Python bindings: If you are releasing a delivered message then I think the default reason for that would be that the delivery failed. I've raised a bug (https://issues.apache.org/jira/browse/PROTON-2883) against the bindings and this will probably be fixed in the next release (0.41).
As an aside, I think the fixed code is a little more verbose than necessary, it could be:
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
event.delivery.local.failed = True
self.settle(event.delivery, event.delivery.MODIFIED)
That's because the default undeliverable
flag is False
, and settling a delivery will update the delivery state.,