JMS Alternative to MQ Strategies on Anypoint - Reliable, Scalable and SRE Focused Messaging


One of the most exciting things about API’s is the ability to invoke them to parse and evaluate a message (i.e. an Order Status object), and, based on the contents of the message, distribute to up to N number of systems to complete the transaction(s). While traditional Message Queuing (MQ) solutions are the obvious Go-To (to ensure reliability, and support for asynchronous messaging), this blog post explores leveraging JMS to handle reliable, synchronous & asynchronous message delivery to an N number of downstream systems. How would you architect the solution?

The first pass is pretty simple:

  1. Expose an HTTP Listener to the source system
  2. Pass the payload to a Scatter-Gather Router
  3. Do some content filtering
  4. Send HTTP Request to the destination systems
  5. Return HTTP 200 to the caller

Gist
Screen-Shot-2019-05-02-at-3.26.55-PM

unreliable

Here we use a Scatter-Gather router to parallelize the work being done to pass the payload to Systems A, B, and C. The payload is copied to each of the routes which are executed concurrently. When all the routes complete, a composite mule event is returned with the results.

The above solution, calling HTTP Request in Scatter-Gather, works so long as one is not worried about the destination systems being offline. Since we are wanting better guarantees of message delivery, approaching a production solution, let’s address destinations being offline.

Mule supports JMS out of the box. A very popular JMS broker, also supported by MuleSoft, is ActiveMQ. Let’s see how we can use ActiveMQ and transactions to prevent dropping messages in failure scenarios.

We are going to update our solution with the Dead Letter Channel from Enterprise Integration Patterns. By passing the message to the JMS queue, we detach a reliability requirement from destination systems. Mule will hold the messages in the JMS queue until the system is online.

Our updated process:

  1. Expose an HTTP Listener to the source system
  2. Pass the payload to a Scatter-Gather Router
  3. Do some content filtering
  4. Drop the message on to the JMS queue for the appropriate system
  5. Return a HTTP 200 to the caller

Gist
Screen-Shot-2019-05-02-at-3.22.17-PM

reliable_jms

And for each destination system:

  1. Stand up a JMS queue listener with transactions
  2. Submit the received payload to an HTTP Request to the appropriate system
  3. Handle errors appropriately: put message back on front of queue on failure1

Now that we have the payload on one or more JMS queues, how do we handle getting the payload off the queue? We know that the destination system will take outages, so we want to use transactions to put messages back on the queue if the flow fails. To handle these failures, the JMS listener Transaction action under the Advanced tab, is set to ALWAYS_BEGIN.

Gist
Screen-Shot-2019-05-02-at-3.25.37-PM

destination_jsm_listener

System B and System C are the same minus the destination URL, as the content filtering and subsequent parsing is handled in the main flow.

After filling out the Flow for System B and System C, we now have four flows that can run independently:

  • Source Listener Flow - listening for new requests, and pushing the payload onto JMS queues
  • Three flows with a JMS listener that is transaction aware to handle a failure of the HTTP Request to the destination system. In the cases where the HTTP request does fail, the payload is put back on the JMS queue for next time, resulting in a robust message delivery system for the order status messages from the source system.

The JMS approach (from the perspective of a caller to this new API), provides a significant benefits and improvements, as follows

  • Performant / Minimal Latency - The response time to the caller is almost immediate, as the payload is passed to the JMS queues.
  • Decoupled and Minimal Dependencies The caller no longer has to know about all three destination systems or their outage schedules, and additional systems can be added without making any changes to the calling system.
  • SRE Focused With appropriate processes, updates to this process can be done with zero outage.

For the destination systems, this solution also has the following benefits:

  • Outages - The system can take an outage, and not miss a message;
  • Self-healing - The flows for the destination systems put the message back on the JMS queue for their system, resulting in reliable message delivery.

1. OmniSuite (Omni3’s Premier Application Overlay for APIM’s and Service Meshes) includes the capability to create dead letter channel / queue monitoring, management and resubmission for API-led, batch and event driven applications. Email us at info@omni3tech.com with the Subject Line of OmniSuite - OmnInitio.