Whilst working on a POC we noticed some very strange behaviour when working with JMS re-deliveries. We were sending a JMS message through a JMS inbound endpoint and purposely throwing an exception using the Test component. Everything worked fine the first time – an exception was thrown and Mule tried to redeliver the message a number of times before giving up. However, we noticed that the same message was not entering our flow when we attempted to send it again in subsequent tries. Our message was being dropped at the connector level.
Internally, the JMS transport uses an idempotent message filter to discard messages that have already been sent. Messages are filtered based on the payload, which in our case is the contents of the JMS message. Mule keeps a record of each message that is sent by applying a SHA256 hash on the payload and stores the hash in an object store.
This is not what we wanted. We wanted to filter out messages based on the JMS message IDs that the JMS broker sends as a header with the JMS message, not the message content. Our flow looked something like this:
This problem stems from the fact that Mule uses its own redelivery policy to redeliver the JMS message. When you define both a roll-back exception strategy with the “maxRedeliveryAttempts” attribute set and a JMS connector with the maxRedelivery attribute set, these two compete against each other. Both of these attributes expect an integer. Mule decides which redelivery policy to use depending on which value is smallest. Consider a scenario where maxRedeliveryAttempts is set to 3, and maxRedelivery on the JMS connector is set to 5. Mule will use its own redelivery policy in favor of the JMS transport redelivery policy since maxRedeliveryAttempts is smaller. In this case, the following exception is thrown when a message is not delivered successfully after a number of retries:
On the other hand, the following exception is thrown when the redelivery policy available in the JMS transport is used:
The expected behaviour is simple; when a JMS connector is defined, the JMS redelivery policy should override that of Mule. If you’re running into this sort of problem, there is a very simple workaround – change how Mule generates message IDs. You can do this by defining your JMS inbound endpoints as follows:
By default, Mule assigns a message ID by generating a SHA256 hash from the payload. The above will assign the JMSMessageID as the Mule message ID instead.