One value, for me, of an ESB framework is to improve the reliability and robustness of a given set of integrated applications. If a message/event producer can communicate with one or more consumers in an asynchronous way, it should. It really makes things simpler. But one thing to avoid in your routing configurations is injecting synchronous calls into an overall asynchronous process.
One nice thing about the particular flavor of ESB we have deployed is that all the routing rules are centrally managed, but widely distributed and executed.
That is, we have a central repository of configuration information, but all the bus managed nodes pull remotely, and store locally, copies of their configuration. We don't have to manually reconfigure every node. And if the repository goes away, the remote nodes really don't care.

We also have a number of external nodes that aren't 'managed' by the bus routing configurations, but they do participate without any coupling to the rules. They only know what queue or topic to listen to, but don't know of any other participants directly. If there is a Reply-To header in the JMS message, they honor it, if it makes sense to send out a reply. To be fair, these services also know where to send faults or rejected message notifications. But this isn't dynamic (but it could be).
When integrating these external nodes to your centrally managed message bus, you have two options. You can have a service 'call out' to the external service then subsequently forward the reply to the next service. Or you can 'call forward' a request to the external service where, in turn, the external service sends the reply directly to the next service in the process as specified by the calling 'call forward' service.
Consider this image of a configuration for a 'call out' type service.

Note the synchronous call in the 'call out'. If the external service happens to be down, the 'call out' service will likely timeout waiting for a response since the reply queue is probably a temporary queue. You are also likely losing a thread waiting for the response.
If the overall process is synchronous, this isn't necessarily a bad thing since you would likely prefer to have the failure be reported back from the actual point of failure. Not at some entrypoint via a timeout. Another benefit of the synchronous 'call out' is that it preserves the original JMS Reply-To header. This header is usually set at the request entrypoint so the reply can make it back to the initial caller for synchronous system requests. See below:

Now consider this image of a configuration for a 'call forward' type service.

The 'call forward' simply hands the message to the external service, but modifies the JMS Reply-To header and sets it to the next destination in the process. This is sometimes knows as the reply-forward pattern.
What's important here is if the external service is unavailable for whatever reason, the messages will be picked up, handled, and forwarded without any timeouts when the external service returns, assuming the overall process is asynchronous.
Using a 'call forward' will step on the original JMS Reply-To value and prevent a synchronous system request from completing. The 'call out' image above implies that the Reply-To is set once for the synchronous call process.
The fallout here in supporting both synchronous and asynchronous processes is that you will have two sets of routing rules for like processes. Ones that support synchronous calls via the 'call out' and ones that support asynchronous calls via the 'call forward'.
One way to solve this is to use a 'Forward-Reply-To' property. Where if it exists in a message, it takes precedence over the JMS Reply-To header. Of course, this would require modifying your external services to honor this property.
But this really just pushes complexity out of the managed bus into external systems and should be avoided unless there is truly a net gain in simplicity.
Leave a comment