Message Design Patterns
If you are implementing a message based system, I suggest reading the canonical resource to get insight on messaging architectures: Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions by Gregor Hohpe y Bobby Woolf.
A short summary of each pattern is available online at http://www.eaipatterns.com/toc.html At the end of the page two case studies are available.
The book is a great resource, you will find there problems and situations you don't even imagine before, with a good analysis of the strategy to solve it.
All the important ones are in the book Enterprise Integration Patterns. Check it out.
Per Enterprise Integration Patterns, the Authors Gregor Hohpe and Bobby Woolf have documented over 60 messaging patterns, grouped into the following six categories :
Message Construction
Message: To exchange a piece of information between two applications connected by a message channel, package the information into a Message, a data record that the messaging system can transmit through a message channel.
Command Message: To invoke a procedure in another application using messaging, use a Command Message to reliably invoke the procedure.
Document Message: To transfer data between applications using messaging, use a Document Message to reliably transfer the data structure.
Event Message: To transmit events from one application to another using messaging, use an Event Message for reliable, asynchronous event notification between the applications.
Request-Reply: To get a response from the receiver when an application sends a message, send a pair of Request-Reply messages, each on its own channel.
Return Address: To inform the replier where to send the reply message, the request message should contain a Return Address.
Correlation Identifier: To allow a requestor to match requests with replies, each reply message should contain a Correlation Identifier, a unique identifier that indicates for which request the message reply is intended.
Message Sequence: To transmit an arbitrarily large amount of data via messaging, break the data into chunks and send them as a Message Sequence, marking each message with sequence identification fields.
Message Expiration: To indicate when a message should be considered stale and thus shouldn’t be processed, set the Message Expiration to specify a time limit how long the message is viable.
Format Indicator: To design a message's data format to allow possible future changes, include a Format Indicator, so that the message specifies what format it is using.
Message Routing
Pipes-and-Filters: To perform complex processing on a message while maintaining independence and flexibility, use the Pipes and Filters architectural style to divide a larger processing task into a sequence of smaller, independent processing steps (Filters) that are connected by channels (Pipes).
Message Router: To decouple individual processing steps so that messages can be passed to different filters depending on a set of conditions, insert a special filter, a Message Router, which consumes a Message from one Message Channel and republishes it to a different Message Channel channel depending on a set of conditions.
Content-based Router: To handle a situation where the implementation of a single logical function (e.g., inventory check) is spread across multiple physical systems, use a Content-Based Router to route each message to the correct recipient based on message content.
Message Filter: To avoid a component receiving uninteresting messages, use a special kind of Message Router, a Message Filter, to eliminate undesired messages from a channel based on a set of criteria.
Dynamics Router: To avoid the dependency of the router on all possible destinations while maintaining its efficiency, use a Dynamic Router, a Router that can self-configure based on special configuration messages from participating destinations.
Recipient List: To route a message to a list of dynamically specified recipients, define a channel for each recipient. Then use a Recipient List to inspect an incoming message, determine the list of desired recipients, and forward the message to all channels associated with the recipients in the list.
Splitter: To process a message if it contains multiple elements, each of which may have to be processed in a different way, use a Splitter to break out the composite message into a series of individual messages, each containing data related to one item.
Aggregator: To combine the results of individual but related messages so that they can be processed as a whole, use a stateful filter, an Aggregator, to collect and store individual messages until a complete set of related messages has been received. Then, the Aggregator publishes a single message distilled from the individual messages.
Resequencer: To get a stream of related but out-of-sequence messages back into the correct order, use a stateful filter, a Resequencer, to collect and re-order messages so that they can be published to the output channel in a specified order.
Composed Message Processor: To maintain the overall message flow when processing a message consisting of multiple elements, each of which may require different processing, use Composed Message Processor to process a composite message. The Composed Message Processor splits the message up, routes the sub-messages to the appropriate destinations and re-aggregates the responses back into a single message.
Scatter-Gather: To maintain the overall message flow when a message needs to be sent to multiple recipients, each of which may send a reply, use a Scatter-Gather that broadcasts a message to multiple recipients and re-aggregates the responses back into a single message.
Routing Slip: To route a message consecutively through a series of processing steps when the sequence of steps is not known at design-time and may vary for each message, attach a Routing Slip to each message, specifying the sequence of processing steps. Wrap each component with a special message router that reads the Routing Slip and routes the message to the next component in the list.
Process Manager: To route a message through multiple processing steps when the required steps may not be known at design-time and may not be sequential, use a central processing unit, a Process Manager, to maintain the state of the sequence and determine the next processing step based on intermediate results.
Message Broker: To decouple the destination of a message from the sender and maintain central control over the flow of messages, use a central Message Broker that can receive messages from multiple destinations, determine the correct destination and route the message to the correct channel.
Message Transformation (translation)
Message Translator: To allow systems using different data formats to communicate with each other using messaging, use a special filter, a Message Translator, between other filters or applications to translate one data format into another.
Envelope Wrapper: To allow existing systems to participate in a messaging exchange that places specific requirements on the message format, such as message header fields or encryption, use an Envelope Wrapper to wrap application data inside an envelope that is compliant with the messaging infrastructure. Unwrap the message when it arrives at the destination.
Content Enricher: To communicate with another system if the message originator does not have all the required data items available, use a specialized transformer, a Content Enricher, to access an external data source in order to augment a message with missing information.
Content Filter: To simplify dealing with a large message, when one is only interested in a few data items, use a Content Filter to remove unimportant data items from a message leaving only important items.
Claim Check: To reduce the data volume of message sent across the system without sacrificing information content, store message data in a persistent store and pass a Claim Check to subsequent components. These components can use the Claim Check to retrieve the stored information.
Normalizer: To process messages that are semantically equivalent, but arrive in a different format, use a Normalizer to route each message type through a custom Message Translator so that the resulting messages match a common format.
Canonical Data Model: To minimize dependencies when integrating applications that use different data formats, design a Canonical Data Model that is independent from any specific application. Require each application to produce and consume messages in this common format.
Messaging Endpoint
Message Endpoint: To connect an application to a messaging channel to send and receive messages, use a Message Endpoint, a client of the messaging system that the application can then use to send or receive messages.
Messaging Gateway: To encapsulate access to the messaging system from the rest of the application, use a Messaging Gateway, a class than wraps messaging-specific method calls and exposes domain-specific methods to the application.
Messaging Mapper: To move data between domain objects and the messaging infrastructure while keeping the two independent of each other, create a separate Messaging Mapper that contains the mapping logic between the messaging infrastructure and the domain objects. Neither the objects nor the infrastructure have knowledge of the Messaging Mapper's existence.
Transactional Client: To allow a client tp control its transactions with the messaging system, use a Transactional Client—make the client’s session with the messaging system transactional so that the client can specify transaction boundaries.
Polling Consumer: To allow an application to consume a message when the application is ready, the aplication should use a Polling Consumer, one that explicitly makes a call when it wants to receive a message.
Event-driver Consumer: To allow an application to automatically consume messages as they become available, the application should use an Event-Driven Consumer, one that is automatically handed messages as they are delivered on the channel.
Competing Consumers: To allow a messaging client to process multiple messages concurrently, create multiple Competing Consumers on a single channel so that the consumers can process multiple messages concurrently.
Message Dispatcher: To coordinate message processing across multiple consumers on a single channel, create a Message Dispatcher on a channel that will consume messages from a channel and distribute them to performers.
Selective Consumer: To allow a message consumer to select which messages it wishes to receive, make the consumer a Selective Consumer, one that filters the messages delivered by its channel so that it only receives the ones that match its criteria.
Durable Subscriber: To avoid a subscribe missing messages while it’s not listening for them, use a Durable Subscriber to make the messaging system save messages published while the subscriber is disconnected.
Idempotent Receiver: To allow a message receiver deal with duplicate messages, design a receiver to be an Idempotent Receiver, i.e. one that can safely receive the same message multiple times.
Service Activator: To create an application service to be invoked both via various messaging technologies and via non-messaging techniques, design a Service Activator that connects the messages on the channel to the service being accessed.
Messaging Channels
Message Channel: To allow one application communicate with another using messaging, connect the applications using a Message Channel, where one application writes information to the channel and the other one reads that information from the channel.
Point-to-Point Channel: To ensure the caller that exactly one receiver will receive the document or perform the call, send the message on a Point-to-Point Channel, which ensures that only one receiver will receive a particular message.
Publish-Subscribe Channel: To allow the sender broadcast an event to all interested receivers, send the event on a Publish-Subscribe Channel, which delivers a copy of a particular event to each receiver.
Datatype Channel: To allow the application to send a data item such that the receiver will know how to process it, use a separate Datatype Channel for each data type, so that all data on a particular channel is of the same type.
Invalid Message Channel: To allow a messaging receiver to gracefully handle receiving a message that makes no sense, the receiver should move the improper message to an Invalid Message Channel, a special channel for messages that could not be processed by their receivers.
Dead Letter Channel: When a messaging system determines that it cannot or should not deliver a message, it may elect to move the message to a Dead Letter Channel.
Guaranteed Delivery: To ensure the sender that a message will be delivered, even if the messaging system fails, use Guaranteed Delivery to make messages persistent so that they are not lost even if the messaging system crashes.
Channel Adapter: To connect an application to the messaging system so that it can send and receive messages, use a Channel Adapter that can access the application's API or data and publish messages on a channel based on this data, and that likewise can receive messages and invoke functionality inside the application.
Messaging Bridge: To allow connection of multiple messaging systems so that messages available on one are also available on the others, use a Messaging Bridge, a connection between messaging systems, to replicate messages between systems.
Message Bus: An architecture that enables separate applications to work together, but in a decoupled fashion such that applications can be easily added or removed without affecting the others, is a Message Bus that connects the middleware between these applications and enables them to work together using messaging.
Systems Management (Monitoring)
Control Bus: To effectively administer a messaging system that is distributed across multiple platforms and a wide geographic area, use a Control Bus to manage an enterprise integration system. The Control Bus uses the same messaging mechanism used by the application data, but uses separate channels to transmit data that is relevant to the management of components involved in the message flow.
Detour: To route a message through intermediate steps to perform validation, testing or debugging functions, construct a Detour with a context-based router controlled via the Control Bus. In one state the router routes incoming messages through additional steps while in the other it routes messages directly to the destination channel.
Wire Tap: To inspect messages that travel on a point-to-point channel, insert a simple Recipient List into the channel that publishes each incoming message to the main channel and a secondary channel.
Message History: To effectively analyze and debug the flow of messages in a loosely coupled system, attach a Message History to the message. The Message History is a list of all applications that the message passed through since its origination.
Message Store: To report against message information without disturbing the loosely coupled and transient nature of a messaging system, use a Message Store to capture information about each message in a central location.
Smart Proxy: To track messages on a service that publishes reply messages to the Return Address specified by the requestor, use a Smart Proxy to store the Return Address supplied by the original requestor and replace it with the address of the Smart Proxy. When the service sends the reply message route it to the original Return Address.
Test Message: To prevent a component garbling outgoing messages due to an internal fault, use Test Message to assure the health of message processing components.
Channel Purger: To remove 'left-over' messages on a channel so that they do not disturb tests or running systems, use a Channel Purger to remove unwanted messages from a channel.
Favour idempotent Message processing: a duplicate message is tolerated without causing "double debits".
Avoid large messages - prefer the "baggage-check" idiom
Avoid message ordering requirements - greatly simplifies burden on infrastructure