Only a few days after announcing improvements to IaaS, Scott Guthrie announced the release of the Windows Azure SDK 2.0. This release improves the Visual Studio tooling, deployment, automation, … And besides that it also introduces some updates to the Windows Azure Service Bus. One of these updates is the new Event-Driven Message Programming Model (or message pump).
How we used to do it
When you create a new Windows Azure project in Visual Studio (a Cloud Service) you get to choose from different Web/Worker Role templates. One of these templates is the following: Worker Role with Service Bus Queue. This project is just a quick start that allows you to see how to receive and process messages coming from a Service Bus Queue from within a Worker Role:
By using the Receive method it was up to you to poll for messages, handle any exceptions, process multiple messages in parallel, Complete the message, … The new support for the Event-Driven Message Programming Model now does most of those things for you. Let’s take a look…
To show this I created a sample application which requests and handles customer approvals. For this I’m using a simple class which contains the Id of the customer:
And then we also have a sample console application which makes sure the queue exists and sends out a message (with the Id of a customer) to the queue. The message is sent each time you press Enter:
This is how sending the messages looks like:
Instead of polling the queue we’ll be using the new message pump. Take a look at how easy it is to get messages from the queue:
The first thing that happens is setting up the options for the message pump by creating a new OnMessageOptions. This class allows us to define a few settings:
- AutoComplete: call Complete on the message after it has been processed (after we leave the OnMessageArrived method)
- ExceptionReceived: the event to raise each time an error occurs
- MaxConcurrentCalls: define how many theads will be processing the queue (for improved performance)
After setting up OnMessageOptions we simply call OnMessage on the queue client with the method to execute each time a message arrives and the options. As you can see from my OnMessageArrived method I simply get the message and process it. I also introduced an exception for every 10th customer to automatically throw an exception. This allows us to test the ExceptionReceived method. Here is the result after I’ve sent a few messages:
As you can see the messages 1 – 9 are being processed very fast, and after processing each message, the message pump will set the message as complete (thanks to the AutoComplete option). But then for customer 10 we get an exception which will raise the ExceptionReceived even. In our case this will call the OnExceptionReceived method. This is typically the place where you’ll want to do something like logging the exception, sending out an email, …
Now the exception might not be a real problem. it could be possible that the issue is fixed the next time we process the message. That’s why it’s important not to handle the exception in the OnMessage action. If you handle the exception the message pump will not know anything went wrong and simply complete the message, which is something you don’t want. You want that, whenever something goes wrong, the message is retried for a few times. If it doesn’t work after a few times it will be placed in the Dead Letter Queue. But remember, this is only possible if you let the message pump handle the exception for you.
Finally we have the MaxConcurrentCalls option which is set to 5. This means that messages will be processed by a maximum of 5 different Threads in parallel, which increases the number of messages being processed on the receiver side. If you set this to 1 and re-run the application you’ll see that messages are being processed one by one. Anyways, this option makes it really easy to use more resources on your machine to process the messages.
Receiver without AutoComplete
Now there are times where you’ll need more control over your message, like when you want to complete it, when you want to abort it, … In that case you can set the AutoComplete option to false:
This code is very similar to the previous example except for 2 small differeneces: AutoComplete is set to false and we’re handling when to complete the message ourselves. This example is fairly simple, it will complete the message only if it’s a valid customer. The great thing about the AutoComplete option is that you can get more control if you need it. What you might notice is that I’m using a retry policy (TOPAZ) on my Complete method. This is to make sure we’re not affected by transient faults (ie: connection loss for a few seconds).
Small but nice
Now while this is a pretty small change, but it will make consuming messages from a Service Bus Queue / Subscriptions so much easier. Read more about the new release in the Release Notes.