While developing a messaging solution is no easy task, operating such a solution in production is equally challenging: A message-based integration solution may produce, route and transform thousands or even millions of messages in a day. We have to deal with exceptions, performance bottlenecks and changes in the participating systems. To make things ever more challenging, components are distributed across many platforms and machines that can reside at multiple locations.
Besides the inherent complexities and scale of integrating distributed packaged and custom applications, the architectural benefits of loose coupling actually make testing and debugging a system harder. Martin Fowler refers to this as the "Architect's dream, Developer's nightmare" symptom: architectural principles of loose coupling and indirection reduce the assumptions systems make about each other and therefore provide flexibility. However, testing a system where a message producer is not aware of who the consumers of this message are, can be challenging. Add to that the asynchronous and temporal aspects of messaging and things get even more complicated. For example, the messaging solution may not even be designed for the message producer to receive a reply message from the recipient(s). Likewise, the messaging infrastructure typically guarantees the delivery of the message but not the delivery time. This makes it hard to develop test cases that rely on the results of the message delivery.
When monitoring a message solution, we can track message at two different levels of abstraction. A typical System Management solution monitors how many messages are being sent or how long it took a message to be processed. These monitoring solutions do not inspect the message data except maybe for some fields in the message header such as the message identifier or the Message History. In contrast, Business Activity Monitoring (BAM) solutions focus on the payload data contained in the message, for example the Dollar value of all orders placed in the last hour. Many of the patterns presented in this section are general enough that they can be used for either purpose. However, because business activity monitoring is a whole new field in itself and shares many complexities with data warehousing (something we have not touched on at all), we decided to discuss the patterns in the context of system management.
System Management patterns are designed to address these requirements and provide the tools to keep a complex message-based system running. We divided this chapter into three sections:
Monitoring and Controlling
A Control Bus provides a single point of control to manage and monitor a distributed solution. It connects multiple components to a central management console that can display the status of each component and monitor message traffic through the components. The console can also be used to send control commands to components, e.g. to change the message flow.
We may want to route messages through additional steps, such as validation or logging. Because these steps can introduce performance overheads, we may want to be able to switch them on and off via the control bus. A Detour gives us this ability.
Observing and Analyzing Message Traffic
Sometimes we need to want to inspect the contents of a message without affecting the primary message flow. A Wire Tap allows us to tap into message traffic.
When we debug a message-based system, is is a great aid to know where a specific message has been. The Message History provides this capability without introducing dependencies between components.
While the Message History is tied to an individual message, a central Message Store can provide a complete account of every message that traveled through the system. Combined with the Message History the Message Store can analyze all possible paths messages can take through the system.
The Wire Tap, Message History, and Message Store help us analyze the asynchronous flow of a message. In order to track messages sent to request-reply services, we need to insert a Smart Proxy into the message stream.
Testing and Debugging
Testing a messaging system before deploying it into production is a good idea. But testing should not stop there. You should be actively verifying that the running messaging system is functioning properly. You can do this by periodically injecting a Test Message into the system and verifying the results.
When a component fails or misbehaves, it is easy to end up with unwanted messages on a channel. During testing it is very useful to remove all remaining messages from a channel so that the components under test do not receive 'leftover' messages. A Channel Purger does that for us.