Jan. 24, 2011, 8:38 a.m.
posted by optimum
Implementing Queued Messaging
Queued Messaging in Windows Communication Foundation enables clients and services to send and receive messages without requiring both applications to be running at the same time. The programming model for using queues basically consists of choosing the appropriate predefined binding or configuring your own custom binding.
Before we dive into Queued Messaging, it's important to review MSMQ and queuing in general.
If you were to call John Smith's office and ask a question, you would be engaging in synchronous messaging with John. You would be making a request and John would be providing a response in real-time.
If you were to call John Smith's office before he arrived, you would leave a voice-mail message with the question. When John Smith arrived at his office, he would see a blinking light to indicate that he had new voice-mail messages. From there, he would dial his voice-mail system and retrieve that message. He would then send a response with the answer by either phone or email.
Your message is being placed in a durable store, John Smith is notified that there are messages available, and he connects to the system to retrieve them.
Queuing is analogous to the voice-mail scenario. Conceptually, a sender initiates a communication by sending a message. Instead of going to voice mail, this message goes to a queue, where it is stored. A receiver application monitors that queue and receives messages at some point after they were delivered.
An MSMQ Primer
Microsoft Message Queue (MSMQ) is the technology Microsoft has provided to support queued messaging on the windows platform. Although MSMQ is not a new feature being introduced with WCF, it may be new to some readers. As such, this next section provides a primer.
We've given an overview of what queued messaging is; now we will begin to look at how queued messaging is done with MSMQ. To begin with, know that there are actually multiple types of queues within MSMQ. They can be placed into one of two bucketsuser-created queues and system queues.
There are several types of user-created queues. Public queues are queues that are visible on the network and listed in Active Directory. Private queues are local to the computer on which they are created. Because their information is not published, an application must know the full path or label of the private queue to access it.
In addition to private and public queues, there are two other types of user-created queues: Administration Queues and Response Queues. Administration queues contain the acknowledgment messages for messages sent within a network. Response queues contain response messages. Response messages are returned to the sender by the receiver, after a message is received.
Systems queues have several types as well: journal, dead-letter, report, and private system queues.
Journal queues can be set up to store copies of messages sent and retrieved from a queue. Separate journals exist on both the client and the server. On the client, there is a single journal queue that logs messages sent to/from that computer. On the server side, a separate journal queue is created for each individual queue, and it tracks only those messages attached to that queue.
When messages are undeliverable or have expired, they are placed in another type of system queue, a dead-letter queue. Dead letters are stored on the computer on which the message expired. When a transactional message dies, it is placed in a variant of dead-letter queue called a transaction dead-letter queue.
Report queues contain messages that identify the route a message took to its destination. In addition, it can also contain test messages. There is one report queue per computer.
The last type is private system queues. These queues store administrative and notification messages needed by the system to process messaging actions.
Dead-Letter Queues and WCF
The dead-letter queue was discussed earlier in the chapter, and it is essentially the queue where expired or otherwise undeliverable messages are sent.
Messages can end up in the dead-letter queue for a number of reasons. This can happen if a queue quota is exceeded, if there is an authorization failure, or if a message expires.
Message delivery can be time sensitive, and the content within messages may have a set lifetime. In these cases, after the expected lifetime, the message should no longer be considered valid. The lifetime of the message can be specified in the binding, specifically the TimeToLive value.
After the TimeToLive has passed, the message is considered expired and sent to the dead-letter queue.
On Windows Vista, WCF v1.0 moves away from a traditional shared dead-letter queue across all applications, providing instead a dead-letter queue for each sending application. By moving away from a traditional shared dead-letter queue, these application-specific dead-letter queues provide a level of isolation between applications and the processing of dead letters targeted for those applications.
This situation can arise, for example, when applications that read messages from a queue cannot process the message immediately because of errors. Aborting the transaction in which the queued message was received leaves the message in the queue so that the message is retried under a new transaction. If the problem that is causing the abort is not corrected, the receiving application can get stuck in an infinite loop, receiving and aborting the same message until the maximum number of delivery attempts has been exceeded and a poison message results.
Handling Poison Messages in WCF
Poison message handling in WCF provides a way for the receiving application to handle poison messages. Poison message handling is configured via the bindings for an endpoint.
The binding exposes four properties that can be set: MaxRetries, MaxRetryCycles, RetryCycleDelay, and RejectAfterLastRetry.
MaxRetries determines the number of times redelivery of a message from the main queue to the application should be attempted. This is typically sufficient if there is a temporary situation that will resolve itself between the initial and final attempts. A common example cited here is a point-in-time deadlock on SQL Server.
MaxRetryCycles identifies the maximum number of retry cycles. A retry cycle consists of putting a message back into the application queue from the retry queue to attempt delivery again.
RetryCycleDelay determines the delay between retry cycles. The combination of the retry cycle and the retry cycle delay provides a way to handle issues in which a longer delay between retries resolves the issue. The delay, which defaults to 10 minutes, provides the capability to compensate for scenarios in which periodic outages interrupting message delivery can be handled smoothly.
RejectAfterLastRetry specifies how to react when the last attempt fails to deliver the message. When true, a negative acknowledgment will be sent to the sender. When false, the message will be sent to the poison queue.
If the message is sent to the poison queue, it can be processed by a separate WCF Queued Message service.
WCF support for handling poison messages is supported only on Windows Vista.
WCF's Bindings for MSMQ
WCF has two bindings for use with MSMQ as a transport: NetProfileMsmqBinding and MsmqIntegrationBinding. The criteria for selecting the appropriate binding concern the type of application used by the client and service, in particular whether they are WCF or MSMQ applications.
In a scenario in which both the client and the server will be using WCF to communicate, the NetProfileMsmqBinding should be used. If either the sender or the receiver is not using WCF for communications, the MsmqIntegrationBinding should be used. This binding maps messages to/from WCF to MSMQ messages based on the direction of the integration (sending or receiving).
Using MSMQ in an integration scenario is covered in Chapter 6, "Legacy Integration."
Creating a WCF Application Using Queued Messaging
Imagine that the bank wanted to provide a value-added service to its customers in the form of bill payment. In this particular scenario, the electric company is one of the payees that the bank would like to support.
This next example is the code used by the bank to implement bill payments using queues:
Creating the Client for the Service
You are now ready to test your queued messaging solution.
Test #1Client and Service Online
The client will call the service, which will utilize queues behind the scenes. The service will pick up the messages from the queue and write out that the bill payments have occurred.
The expected outcome is shown in Figure.
4. Screenshot of the resulting test.
Test #2Service Offline When Message Sent, Online Later
In this test, we will simulate a disconnected scenario.
Notice that the service comes online, detects the messages, and processes the messages the client sent earlier.
This is because the messages were placed on the queue by the client, and the service retrieved the messages from the queue when it went online.