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)
You need to take the time to read the specification and understand what the various dispositions mean both on the target and at the source.
Released means that the source should treat the message as having not been processed and return it to an initial state, where Rejected means the message is considered invalid and should enter a terminal state. The proper outcome for recording failed attempts is the Modified disposition which offers a delivery failed flag that indicates the delivery count should be incremented, which is what the server is going to use to eventually DLQ the message after a sufficient number of failed attempts.
The AMQP specification is fairly explicit about what happens with the delivery count based on the outcome received so a reading of that can help, but as a simple rule the Modified(deliveryFailed=true) disposition is the one sure way to have the delivery count updated on the server.