JMS message rollback and redelivery with Mule

motif

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 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 3.x 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 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 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 a message. So for example if you set this property to 5, then Mule will try to 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? 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,


We'd love to hear your opinion on this post


4 Responses to “JMS message rollback and redelivery with Mule”

  1. Gee this looks familiar. 😉

  2. […] Ford, on June 23rd, 2011 at 8:13 am […]

  3. Hi!
    Thanks for an interesting post.

    I think the problem that many users have is that they would like to implement a similar scenario as the one you describe but they also need to use for example the message enricher and the jdbc transport to add information to the message before committing the result to another queue. The problem with this scenario is that it’s not possible to exclude the jdbc:outbound-endpoint from the current jms:transaction. The solution to this would be xa:transactions, but if performance is an important issue I don’t think that xa:transactions is an option.

  4. Great article !!