Estou usando o Apache ActiveMQ Artemis 2.40.0 como broker e o Qpid Proton Python 0.39.0 ( python-qpid-proton
) como cliente AMQP 1.0.
O objetivo é que as mensagens sejam reenviadas até um limite configurado ( max-delivery-attempts
) quando o consumidor explicitamente não reconhece (NACK) uma mensagem, usando o release(delivered=True)
método do Proton MessagingHandler
.
Configurei o broker.xml
no Artemis com o seguinte <address-setting>
bloco:
<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>
O código Python:
Aqui está um trecho do on_message
método no meu consumidor Qpid Proton:
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)
Apesar de usar release(delivered=True)
, o Artemis parece reenviar a mensagem indefinidamente (ignorando o <max-delivery-attempts>
), a menos que eu mude para reject(event.delivery)
, que envia imediatamente a mensagem para o DLQ na primeira falha.
Também tentei adicionar a tag <persist-delivery-count-before-delivery>true</persist-delivery-count-before-delivery>
ao broker.xml
, mas sem sucesso.
Comportamento esperado:
Em seguida
release(delivered=True)
, Ártemis deve:- Contar uma tentativa de reentrega
- Tente novamente a mensagem com base em
max-delivery-attempts
eredelivery-delay
- Envie para o DLQ após 5 tentativas frustradas
release(delivered=True)
deve se comportar como um NACK suave , conforme descrito na documentação do Proton
Problema:
Artemis continua reenviando a mensagem infinitamente , nunca contando para max-delivery-attempts
. Parece que a contagem de entrega não está sendo persistida ou reconhecida como esperado do Proton.
O que eu tentei:
- Explícito
release(delivery, delivered=True)
- Usando
reject()
(funciona, mas não é o comportamento que eu quero) - Adicionando
<persist-delivery-count-before-delivery>
à configuração do broker (quebra o esquema no Artemis 2.40.0) - Verificou-se que os Protons
on_released
,on_settled
, nãoon_rejected
são acionados emrelease(delivered=True)
Pergunta:
- É
release(delivered=True)
suportado pelo Artemis 2.40.0 como uma forma de incrementar a contagem de entregas? - Existe uma maneira correta/melhor de fazer NACK no Proton Python para que o Artemis rastreie as reentregas?
- Existe um broker alternativo ou configuração do Proton para dar suporte a essa lógica de repetição?
Desde já, obrigado!
RESOLUÇÃO:
Eu não estava atualizando o objeto de estado local antes de liberar a mensagem. Então, para usar a max-delivery-attempts
política com o DLQ
definido em broker.xml, ele deve completar estas propriedades locais:
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)
Você precisa reservar um tempo para ler a especificação e entender o que as várias disposições significam tanto no destino quanto na origem.
Released significa que a fonte deve tratar a mensagem como se não tivesse sido processada e retorná-la a um estado inicial, onde Rejected significa que a mensagem é considerada inválida e deve entrar em um estado terminal. O resultado adequado para registrar tentativas com falha é a disposição Modified, que oferece um sinalizador de falha de entrega que indica que a contagem de entrega deve ser incrementada, que é o que o servidor usará para eventualmente DLQ a mensagem após um número suficiente de tentativas com falha.