Please form a queue, for poison.

In the previous post about using MSMQ to facilitate One-Way-Calls I covered some of the basics of setting up a MSMQ binding. In that scenario if a consumer of that end point sent a malformed message or the message became corrupted in transmission, the service would either discard it and there would be no feedback on the problem or far worse the service may attempt to process the poison message again and again getting stuck in a loop. Such a processing loop would prevent a service from continuing normal operation of being able to handling subsequent messages. MSMQ 3.0 under Windows XP and Windows Server 2003 has only the ability to retry a failed message once, before it either simply drops the message or faults the channel. A message that is un-processable in this fashion is referred to as a poison message. The wise choice is therefore to use MSMQ 4.0 under Windows Server 2008/Vista/Windows 7 which offers more suitable alternatives.

One alternative I would like to discuss here is using a poison queue. The basic concept is; the primary (msmq based) service which has an “important function” (unlike our unimportant notification service in the previous msmq post) has an associated poison queue. Messages are moved into this queue when they are determined to in-fact be poison. These messages can then be dealt with by a separate service or just human monitoring.

A setup of a poison queue is achieved by exposing a second service and endpoint binding with an identical address but with a ;poison suffix (as well as making use of a different bindingConfiguration):

<services>
   <service name = "MyService">
      <endpoint
         address  = "net.msmq://localhost/private/ImportantQueue" 
         binding  = "netMsmqBinding"
         bindingConfiguration = "importantMsgHandling"
         contract = "IImportantService" 
      />
      <endpoint
         address  = "net.msmq://localhost/private/ImportantQueue;poison"
         binding  = "netMsmqBinding"
         contract = "IImportantService"
      />
   </service>

   <bindings>
      <netMsmqBinding>
         <binding name = "importantMsgHandling"
            maxRetryCycles= "2" 
            receiveRetryCount = "3"
            receiveErrorHandling="Move"
            retryCycleDelay = "00:00:10">
         </binding>
      </netMsmqBinding>
   </bindings>
</services>

I hit a few hiccups in this run through so I’ve added a trouble shooting section at the bottom of the post.

The other key configuration features to note on this configuration setup are (and illustrated below):

  • receiveErrorHandling – with the options of: Fault, Drop, Reject and Move. With our chosen option of move meaning once the error handling process has completed it will be moved to our poison queue
  • receiveRetryCount – number of immediate attempts to process the message.
  • maxRetryCycles – number of subsequent attempts to process message.
  • retryCycleDelay – time between retry cycles.
Poison Queue Message Processing

Poison Queue Message Processing

Once our poison message has failed to be processed, it is shifted to the “poison” sub-queue as shown in this Computer Management screen shot:

Computer Management - Poison Queue

Computer Management - Poison Queue

At this point we can do a few things, from the simplest option of having an admin user review the messages in this poison queue, to a more sophisticated approach of having a separate service attempt to process these poison messages with some more sophisticated logic. Juval Lowy (a while ago now) has published an MSDN Magazine article on an even more sophisticated error handling approach for dealing with a poison messages dubbed a “Response Service”. In essence a (potentially) disconnect client is given the ability to receive feedback via a separate queue. Message responses are generated based on the original flawed message. I plan to implement this approach if at some point the medical demo application I started a few weeks ago warrants it.

Troubleshooting:
On a side note under Windows 7 and Vista the user you are logged in as will not have access to listen for messages on a given port. You’ll quickly see the AddressAccessDeniedException:
HTTP could not register URL http://+:8000/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details)

AddressAccessDeniedxception

AddressAccessDeniedxception


To resolve this simply grant yourself permission to access the port via an administrator command prompt call to netsh.exe

netsh http add urlacl url=http://+:8000/ user="DOMAIN\User Name"

Note: “Domain” can be the machine name if you’re not on a domain. Add a few other ports you might be using too, i.e 8005 for the ServiceModelEx logbook service. For more info refer to this blog post, which has a detailed explanation and in the comments there is discussion of issues on other systems such as Windows Server 2003.

Advertisements

One Way Street

One-Way-Calls in WCF are an effective way to perform an action that you don’t care when (or even if) it completes. If you do care about tracking success or logging failure I’ll have a follow up post to cover that. The simplest example is something along the lines of a non-critical system status update; achieved by sending an email, a text message or an even more modern tweet post, informing someone of an system state/event.

One Way

To begin with lets get a one way method call sent off to a service that may (or may not) be currently active. To achieve this I will be making use of Microsoft’s Message Queuing system (MSMQ). At the end of the post I’ll have a brief discussion on MSMQ.

Now, the key attribute to achieve one-way is:

[OperationContract(IsOneWay = true)]

It is applied to methods on the Service Contract interface. A quick thing to note here is for the NetMsmq Binding in WCF the IsOneWay is required as the queue does not support a duplex channel scenario, and if you miss-configure your methods this exception will quickly pop up on load:

Contract Requires Two-Way Exception

Contract Requires Two-Way Exception

To configure your App.Config file we make use of the net.Msmq binding. This config follows the same pattern in previous posts. This endpoint can exist alongside other types of endpoints, but should be separated into it’s own manager that will handle all the OneWay endpoints/methods.

<services>
   <service name="Notification.NotificationImplementation.OneWayNotificationManager">

      <endpoint name="netMsmq_IOneWayNotificationService"
         address="net.Msmq://MACHINE_NAME/oneWayNotificationService"
         binding="netMsmqBinding"
         bindingConfiguration="netMsmq"
         contract="Notification.NotificationServiceContract.IOneWayNotificationService" />

   </service>
</services>

Now for the full interface definition, it’s as just like the previous examples except with the IsOneWay attribute. Another addition I’ve included here is DeliveryRequirements.Required it assist in defining a solid rule that this interface is designed only for MSMQ calls. The other 2 options on the attribute are ‘NotRequired’ and ‘Allowed’.

[ServiceContract(Name = "IOneWayNotificationService", Namespace = "http://your.domain/2009/")]
[DeliveryRequirements(QueuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Required)]
public interface IOneWayNotificationService
{
   [OperationContract(IsOneWay = true)]
   [TransactionFlow(TransactionFlowOption.Allowed)]
   void SendNotification(NotificationRequest request);
}

Creating the host is identical to previous examples:

ServiceHost oneWayNotificationManager = new ServiceHost();

One additional approach to make life just that little bit easier, making use of ServiceModelEx‘s method VerifyQueue() to create the actual queue and verify access to it. As a reminder my ServiceModelEx overview is here.

//With a quick and dirty zero index array element if you only have 1 endpoint.
ServiceModelEx.QueuedServiceHelper.VerifyQueue(oneWayNotificationManager.Description.Endpoints[0]);

//Or iterate over each endpoint in a loop
foreach(ServiceEndpoint endpoint in oneWayNotificationManager.Description.Endpoints)
   ServiceModelEx.QueuedServiceHelper.VerifyQueue(endpoint);

oneWayNotificationManager.AddErrorHandler();
oneWayNotificationManager.Open();

Now calling the method from a client application (or other service) is just like any other call except there will be no response.

using ( OneWayNotificationServiceProxy proxy = new OneWayNotificationServiceProxy() )
{
   NotificationRequest request = new NotificationRequest();
   request.someProperty = true;

   proxy.SendNotification(request);
}

The client sending the call will need to have an net.Msmq endpoint configured in it’s App.Config:

<system.serviceModel>
   <client>
      <endpoint name="netMsmq_IOneWayNotificationService"
         address="net.Msmq://MACHINE_NAME/OneWayNotificationService"
         binding="netMsmqBinding"
         bindingConfiguration="netMsmq"
         contract="Notification.NotificationServiceContract.IOneWayNotificationService" />
      </client>
   </system.serviceModel>

It’s as simple as that, open up the Computer Management Console to view the messages show up in the queue. In the next post I’ll go into some more detail about the queues.

Computer Management Console

Computer Management Console

MSMQ

There’s a lot to say about MSMQ, and a variety of ways to use with WCF. In this example basically it will hold the message until our service is ready to use it, and in this post we’re not concerned if something goes wrong. Two quick things I want to bring up about MSMQ are:

  1. It is not installed by default; you need perform a few steps – MS Technet has the instructions.
  2. To make use of “Public Queues” the system needs to be part of a domain with Active Directory, otherwise all you have access is to “Private Queues”. To directly quote the MSMQ Faq:
    • “MSMQ utilizes Active Directory for security information related to encryption and decryption, or message authentication. MSMQ also uses Active Directory for public queue lookups – in this way the sending or receiving applications do not need to know the machine-name of the computer hosting the destination queue.”