Some types of MuleSoft applications have zero tolerance for message loss. An online order purchasing application is a good example. Losing even one message during an online purchase order would have a direct impact on a company’s sales revenue.
Fortunately, there are ways to ensure reliable message delivery when implementing a MuleSoft application. One approach is to use transactional Mule transports, such as VM and JMS. By taking advantage of the built-in transactional support in VM and JMS transports, messages will be delivered reliably between an inbound endpoint and an outbound endpoint or between message processors within a Mule flow.
However, some transports, such as HTTP, File and FTP do not support transactions. If an application receives messages through an inbound HTTP listener, there is a potential for message loss if a message processor throws an exception. For non-transactional transports, a design approach called a reliability pattern can be used to achieve reliable message delivery.
A reliability pattern is a design approach that ensures reliable message delivery by combining a non-transactional inbound transport (HTTP) with a transactional outbound transport (VM) in a synchronous flow called a reliable acquisition flow. The reliable acquisition flow is responsible for receiving the inbound message, validating the message and placing the message on a queue using a VM or JMS connector. The application business logic is implemented in a separate flow called the application logic flow.
It is important to note that the reliable acquisition flow should be configured with a synchronous processing strategy. This will ensure that the message is validated and delivered to the outbound VM endpoint on a single thread. Also, the inbound VM endpoint in the application logic flow should be configured as transactional to allow for rollbacks if an exception occurs during message processing.
The following Mule flow shows an example of how to implement a reliable acquisition flow coupled with an application logic flow.
Following are the steps of the process flow shown above:
- The inbound HTTP listener receives a message synchronously in the reliable acquisition flow
- The payload is set, logged and validated
- If the message is valid, the message is sent to the outbound VM endpoint and placed in a queue
- The inbound VM endpoint in the application logic flow picks up the message from the queue, starts a new transaction and sets the payload.
- Application business logic is performed on the message and either completes successfully or throws an exception
- If an exception is thrown, the rollback exception strategy will catch the exception and rollback the message to its original state.
- The application logic flow will reattempt to process the message up to the maximum number of retries configured in the rollback exception strategy.
- If the maximum number of retries are exhausted, the message will be delivered to a JMS queue for reprocessing at a later time.
Example Source Code
The source code for the example Mule flow has been provided below.
Here are a few notes regarding the sample code:
- The sample code has an ActiveMQ connector defined. ActiveMQ is available for download at http://activemq.apache.org/
- The URL to run the sample code on your local environment is http://localhost:8081/test/reliable?input=fail
- Valid input query parameter values are success or fail. Passing a fail input value will trigger the rollback exception strategy.
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/> <jms:activemq-connector name="Active_MQ" username="admin" password="admin" brokerURL="tcp://localhost:61616" validateConnections="true" maxRedelivery="2" doc:name="Active MQ"/> <flow name="Reliable-Acquisition-Flow" processingStrategy="synchronous"> <http:listener config-ref="HTTP_Listener_Configuration" path="/test/reliable" allowedMethods="POST" doc:name="HTTP"/> <set-payload value="#[message.inboundProperties.'http.query.params'.input]" doc:name="Set Payload"/> <logger message="#[payload]" level="INFO" doc:name="Log Original Payload"/> <validation:is-true message="Input invalid: Must be either "success" or "fail"" expression="#[payload.equalsIgnoreCase("success") || payload.equalsIgnoreCase("fail")]" doc:name="Validate the Payload"/> <vm:outbound-endpoint exchange-pattern="one-way" path="input" doc:name="VM"/> </flow> <flow name="Application-Logic-Flow" processingStrategy="synchronous"> <vm:inbound-endpoint exchange-pattern="one-way" path="input" doc:name="VM"> <vm:transaction action="ALWAYS_BEGIN"/> </vm:inbound-endpoint> <set-payload value="#[payload]" doc:name="Set Payload"/> <validation:is-false message="Exception thrown" expression="#[payload.equalsIgnoreCase("fail")]" doc:name="Throw Exception when "fail""/> <logger message="Completed Successfully!" level="INFO" doc:name="Log Success"/> <rollback-exception-strategy maxRedeliveryAttempts="2" doc:name="Rollback Exception Strategy"> <logger message="Transaction failed, trying again" level="INFO" doc:name="Log Retry"/> <on-redelivery-attempts-exceeded> <jms:outbound-endpoint queue="error-queue" connector-ref="Active_MQ" doc:name="JMS (Dead Letter Queue)"> <jms:transaction action="NONE"/> </jms:outbound-endpoint> </on-redelivery-attempts-exceeded> </rollback-exception-strategy> </flow>
Learn more about Mule Reliability Patterns and Transaction Management by visiting the following URLs: