Reading Time: 6 minutes

I have seen a lot of users and customers looking for a solution for this following use case – you have a JMS message in transaction inside Mule and suddenly, before committing something bad happened. You want to rollback this message and retry to deliver. If unable to commit for a specific number of times redirected to a dead letter queue (DLQ).

Pre-requisites

To run this example, you will require Mule and Apache ActiveMQ(5.4.x/5.5.x).

The Flow

In our Mule flow we are going to do the following:

  • JMS inbound endpoint, starting the JMS transaction
  • A component to do some business logic, this component will throw a custom exception say “org.exceptions.MyException”
  • JMS outbound endpoint, Commit the result to another queue/topic

At step 2, as we can see the exception will be thrown. What we want to do here is to Rollback. So let’s see how our exception strategy will look:

The above strategy will rollback the message if the exception type = “org.exceptions.MyException”, otherwise it will commit. You can define an outbound endpoint where the message will be committed. The full Mule flow is as follows:

We need to make sure that the message redelivers only certain number of times and once failed,is redirected to a DLQ.

The Mule JMS connector has an attribute “maxRedelivery” that defines the maximum number of times to try to redeliver a message. So for example if you set this property to 5, then Mule will try to redeliver this message 5 times before sending it back to a DLQ. Note that is message is delivered once the first time plus 5 redelivery attempts.

By default Mule will redeliver back the message immediately once the exception occurs, What if you want to add a redelivery delay on each redelivery? ActiveMQ comes with this great feature: RedeliveryPolicy.  We will use spring beans to initiate our JMS connector and configure the RedeliveryPolicy on the ActiveMQ connectionFactory used by the JMS connector. There are various parameters defined in the redeliveryPolicy like initialRedeliveryDelay and deliveryDelay etc. For all configuration options see the Redelivery Policy topic in the Active MQ documentation.

<spring:beans>

<!-- Redelivery Policy -->

<spring:bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">

<spring:property name="maximumRedeliveries" value="5"/>

<spring:property name="initialRedeliveryDelay" value="5000"/>

<spring:property name="redeliveryDelay" value="2000"/>

<spring:property name="useExponentialBackOff" value="false"/>

<spring:property name="backOffMultiplier" value="2"/>

</spring:bean>

<!-- ActiveMQ Connection factory -->
<spring:bean id="amqFactory" class="org.apache.activemq.ActiveMQConnectionFactory" lazy-init="true">

<spring:property name="brokerURL" value="failover:(tcp://localhost:61616)" />

<spring:property name="redeliveryPolicy" ref="redeliveryPolicy">

</spring:property>

</spring:bean>

</spring:beans>

 <!-- Mule JMS Connector -->

<jms:activemq-connector name="jmsConnector" connectionFactory-ref="amqFactory" maxRedelivery="5" persistentDelivery="true" specification="1.1"/>
 


The above configuration will rollback first time but will wait for the “initialRedeliveryDelay” that is 5 seconds, then other times it will add a delay “redeliveryDelay” of 2 seconds for any other rollbacks. You could set “useExponentialBackOff” parameter if you you want to add an exponential delay on each rollback.

Please download this example Mule App from here

How to view Dead Letter Queue?

Activemq 5.x by default will only store persistent messages to a DLQ. If you want to store non-persistent message, then you need to add processNonPersistent=”true” to your deadLetterStrategy. Please see the following snippet for ActiveMQ broker configuration, this will store non-persistent message to a DLQ and ActiveMQ will create DLQ for each queue

<deadLetterStrategy>
  <individualDeadLetterStrategy queuePrefix="DLQ."
  useQueueForQueueMessages="true" processNonPersistent="true"/>
</deadLetterStrategy>

You could also define a shared DLQ, which will share the same DLQ for every queue. To know more please see Redelivery and DLQ Handling.
That’s it, you are now ready to run your test case. Try sending a persistent message to the queue “in”. You should see the poisoned message sent to the default Activemq.DLQ or DLQ.in based on what strategy you have defined

NOTE: make sure you have activemq-core jar in your MUle application classpath before running this example,

latest report
Learn why we are the Leaders in API management and iPaaS