Search code examples
activemq-artemis

ActiveMQ Artemis DLQ queue assignment


Using Artemis 2.31.2, I am creating multiple queues (queue1 .. queue8) in the consumer using:

session = connection.createSession(true, Session.SESSION_TRANSACTED);
session.createConsumer(session.createQueue(queueName));

In broker.xml I have this configuration which assigns dead letters to individual queueName.DLQ on session.rollback()

<dead-letter-address>DLA</dead-letter-address>
<max-delivery-attempts>2</max-delivery-attempts>
<auto-create-dead-letter-resources>true</auto-create-dead-letter-resources>
<dead-letter-queue-prefix></dead-letter-queue-prefix> <!-- override the default -->
<dead-letter-queue-suffix>.DLQ</dead-letter-queue-suffix>

I attempt to process the message and rollback on failure.

try{ "process message..." }  
catch (Exception e) {   
  try {     
     session.rollback();   
  } catch (JMSException ex) {   
    LOGGER.info("JMSException in session rollback: {}", ex.getMessage());   
  }   
  LOGGER.error("Exception in queue: {} e: {}", queueName, e); 
}

which works fine as long as I do not setMessageListener on the queueName.DLQ but when I set setMessageListener on the queueName.DLQ, DLQ messages are assigned to random queueName.DLQ, not the queueName which the rollback happened 2 times. For example message rolled back from queue1 gets copied to queue5.DLQ, next time it gets copied to queue3.DLQ, etc...

session.createConsumer(session.createQueue("DLA::" + queueName + ".DLQ")).setMessageListener(message -> {
  try {
    LOGGER.info("DLQ msg in queue: {}", queueName);
    message.acknowledge();
  } catch (JMSException e) {
    LOGGER.info("JMSException acknowledging a DLQ message: {}", e.getMessage());
  }
});

Any ideas would be appreciated.


Solution

  • My guess is that you are creating the MessageConsumer on the DLQ (e.g. DLA::queue1.DLQ) and setting the MessageListener before rollback is invoked. If that's the case then that means the creation of the consumer is triggering the creation of the DLQ rather than the broker creating it automatically based on <auto-create-dead-letter-resources>true</auto-create-dead-letter-resources>. This circumvents a very important step which the broker would normally execute - setting the filter on the dead letter queue. This is noted in the documentation which states:

    The address created will be the one defined by the dead-letter-address. A MULTICAST queue will be created on that address. It will be named by the address to which the message was previously sent, and it will have a filter defined using the property _AMQ_ORIG_ADDRESS so that it will only receive messages sent to the relevant address.

    Since this step is not executed in your case every queue on the dead-letter address will receive every message instead of just the ones that it should.

    You should allow the broker to automatically create the dead-letter resources itself without interference from your application or you should statically configure them as needed and disable auto-creation.