Search code examples
jakarta-eejmsactivemq-classicmessage-driven-bean

Specify DeadLetterQueue for redelivered messages in MessageDrivenBean


I've create a MDB that reads messages from ActiveMQ

@MessageDriven(name = "MessageReaderEJB",
    activationConfig = {
            @ActivationConfigProperty(propertyName = "acknowledgeMode",
                    propertyValue = "Auto-acknowledge"),
            @ActivationConfigProperty(propertyName = "destinationType",
                    propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "destination",
                    propertyValue = "archive.>")

    })

@Slf4j
public class ArchiveMessageListenerBean implements MessageListener {
   ...
   @Override
   public void onMessage(Message inMessage) {
   ...
   }
   ...
}

and my glassfish-ejb-jar.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-ejb-jar PUBLIC "-//GlassFish.org//DTD GlassFish 
Application Server 3.1 EJB 3.1//EN"
    "http://glassfish.org/dtds/glassfish-ejb-jar_3_1-1.dtd">
<glassfish-ejb-jar>
<enterprise-beans>
    <ejb>
        <ejb-name>MessageReaderEJB</ejb-name>
        <mdb-connection-factory>
            <jndi-name>jms/jms.connectionFactory</jndi-name>
        </mdb-connection-factory>
        <mdb-resource-adapter>
            <resource-adapter-mid>ActiveMQ-Resource-Adapter-5.14.1</resource-adapter-mid>
        </mdb-resource-adapter>

    </ejb>
</enterprise-beans>
</glassfish-ejb-jar>

If there is an exception thrown in onMessage() there are some redeliveries and after max. redeliveries the message will be send to ActiveMQ.DLQ. How can I configure that the message will be send to my.error.queue instead of ActiveMQ.DLQ?

Thanks for help!


Solution

  • you can only specify a specific dead letter queue prefix for a given queue or topic. You can use Camel if you want to route messages from DLQ to another one based on JMSDestination messages header.

    The broker transmits the default delivery policy that he prefers to a client connection in his BrokerInfo command packet. But the client can override the policy settings by using the ActiveMQConnection.getRedeliveryPolicy() method:

    RedeliveryPolicy policy = connection.getRedeliveryPolicy();
    policy.setInitialRedeliveryDelay(500);
    policy.setBackOffMultiplier(2);
    policy.setUseExponentialBackOff(true);
    policy.setMaximumRedeliveries(2);
    

    Once a message's redelivery attempts exceeds the maximumRedeliveries configured for the Redelivery Policy, a "Poison ACK" is sent back to the broker letting him know that the message was considered a poison pill. The Broker then takes the message and sends it to a Dead Letter Queue so that it can be analyzed later on.

    The default Dead Letter Queue in ActiveMQ is called ActiveMQ.DLQ; all un-deliverable messages will get sent to this queue and this can be difficult to manage. So, you can set an individualDeadLetterStrategy in the destination policy map of the activemq.xml configuration file, which allows you to specify a specific dead letter queue prefix for a given queue or topic. You can apply this strategy using wild card if you like so that all queues get their own dead-letter queue, as is shown in the example below.

    <broker>
         <destinationPolicy>
            <policyMap>
              <policyEntries>
                <policyEntry queue=">">
                  <deadLetterStrategy>
                       <individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true"/>
                  </deadLetterStrategy>
                </policyEntry>
              </policyEntries>
            </policyMap>
        </destinationPolicy>
    </broker> 
    

    See the Redelivery Policy section for some more detail on the policy options.

    http://activemq.apache.org/message-redelivery-and-dlq-handling.html