Delivering training is a great opportunity to learn how software can be improved. Trainees come up with questions on how they want to use the software in ways you’d never dream about. Let’s take my case. While delivering Mule training, I was asked about the Idempotent Message Filter’s ability to rollback its state. This simple XML snippet helps explain the question:
An XA transaction begins when the message is consumed from the VM queue “in”. The queue joins the transaction and the message is passed on to the Idempotent Message Filter. The Idempotent Message Filter records the message ID if it doesn’t exist or drops the message if the ID has already been recorded. Should the message pass through, it’s processed by the component Foo and then placed on the “out” queue which is also a participant in the transaction. In the event that something goes wrong in the flow, the message is put back on the VM queue “in”. But what about the Idempotent Message Filter? Will it remove the message ID recorded in the failed transaction? The answer is no. The reason is that the Idempotent Message Filter is unaware of the transaction, and therefore, never participates in it. The problem with this behaviour is that re-processing the message will result in the message being treated as a duplicate and dropped by the Idempotent Message Filter since the filter didn’t rollback the recorded message ID. Clearly this is unacceptable in certain situations!
While there are ways to minimise the problem of having an Idempotent Message Filter in an inconsistent state, the only foolproof way is to have the Idempotent Message Filter participate in the distributed transaction. The Transaction Aware Object Store, part of the Mule Ricston Module, was developed to address this need.
In the above snippet, the Idempotent Message Filter’s object store is injected with TransactionAwareObjectStore: an object store which joins an XA transaction if one is present. What this means is that the message ID is recorded by the Idempotent Message Filter if, and only if, the transaction has committed. Of course, using this object store has a penalty on performance. However, sometimes, utilising the TransactionAwareObjectStore class is necessary since it might be critical for your business to have 100% consistent state at all times.