Recently Microsoft has announced the new Windows Azure Service Bus Push Notification Hubs. And many samples and videos have been posted on the new feature. To support Notification Hubs, a new Service Bus previews features library (Microsoft.ServiceBus.Preview.dll) has been released to NuGet gallery. In this series of post I’ll drill down to several other cool new features and important enhancements contained in this library.
[This post series is based on preview features that are subject to change]
Message Pump
Up until now, if you want to receive messages from a Windows Azure Service Bus queue or topic/subscription, you need to periodically poll the queue or the subscription asking for new messages. The following code should look quite familiar:
while (!IsStopped) { ... BrokeredMessage receivedMessage = null; receivedMessage = Client.Receive(); if (receivedMessage != null) { ... receivedMessage.Complete(); } ... Thread.Sleep(10000); }
Actually, the above code is a simplified version of auto-generated code when you used “Worker Role with Service Queue” template to add a new Worker Role. This pattern works well in this case because you do need a loop or other blocking wait in your Run() method to keep your role instances running. However, there are a couple of problems with this pattern. First, the Thread.Sleep() calls cause unnecessary delays in the system – the above code can only respond to at most one message every ten seconds. This kind of throughputs is unacceptable to many systems. Of course we can reduce the sleep interval, let’s say to get it down to 1 second. This makes the system more responsive, but it creases number of service calls by 10 times. Polling at a 1 second interval generates 86,400 billable messages (60 * 60 * 24) per day, even if most of them are NULL messages. That doesn’t cost much – at the price of $0.01 per 10,000 billable messages it translates to 8.64 cents per day. However that IS a lot of service calls. Second, in some applications, especially client applications, event-driving programming model is often preferred. Service Bus preview features changes all these. Underneath it uses long-polling so that you don’t occur service transactions as often. And you get immediate feedbacks when a new message shows up in the pipeline. For instance, let’s say if default long-polling timeout is 1 minute, the number of billable messages reduces to 1,440 (60 * 24) per day. That’s quite a improvement in terms of reducing number of service calls. In addition, the preview library supports event-driven model instead of polling - you can simply wait for OnMessage events.
The following is a walkthrough of using the preview library. The walkthrough uses a simple WPF application that allows you to send and receive messages.
- Create a new WFP application.
- Install the preview NuGet package:
install-package ServiceBus.Preview
- Get a minimum UI in place:
<Window x:Class="EventPumpWPF.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Message-Driven Messaging" Height="350" Width="525" FontSize="18"> <StackPanel Grid.Column="0"> <TextBox x:Name="messageText" /> <Button x:Name="sendMessage" Click="sendMessage_Click_1">Send</Button> <ListBox x:Name="messageList"/> </StackPanel> </Window>
- Modify the code-behind:
public partial class MainWindow : Window { const string conString = "[SB connection string]"; const string queueName = "workqueue"; QueueClient mSender, mReceiver; public MainWindow() { InitializeComponent(); mSender = QueueClient.CreateFromConnectionString(conString, queueName); mReceiver = QueueClient.CreateFromConnectionString(conString, queueName, ReceiveMode.ReceiveAndDelete); mSender.OnMessage((m) => { messageList.Dispatcher.Invoke(() => { messageList.Items.Add(m.GetBody<string>()); }); }, 1); } private void sendMessage_Click_1(object sender, RoutedEventArgs e) { mSender.Send(new BrokeredMessage(messageText.Text)); messageText.Text = ""; } }
- And that’s all! The only line that is new is highlighted – very simple and very straightforward.
If you’ve observed closely, you might notice there’s a second parameter (highlight in green) to OnMessage() method. This method controls how many concurrent calls to the callback (the first parameter) can occur. To illustrate the effect of this parameter, let’s modify the code a little.
- First, we add a randomizer to MainWindow class:
Random rand = new Random();
- And we’ll update or message handler to add a random sleep. This is to simulate fluctuations in processing time:
mSender.OnMessage((m) => { Thread.Sleep(rand.Next(1000, 3000)); messageList.Dispatcher.Invoke(() => { messageList.Items.Add(m.GetBody<string>()); }); }, 1);
- Finally, we change the sending code to send 10 messages instead of 1:
for (int i = 0; i < 10; i++) { mSender.Send(new BrokeredMessage(messageText.Text + i.ToString())); }
- Now launch the program and send a message “m”, which morphs into ten messages. The code takes a while to execute because of the random sleeps and there’s only a single entry is allowed to the callback. But because the single-entrance limit, you eventually get all messages back in-order.
- Now modify the second parameter (highlighted in green) to 10. Run the app again. Now the code takes shorter time to execute because the callback can be invoked multiple times at the same time. But the message display may be out-of-order:
There you go. A very cool addition to Service Bus provided by Service Bus preview features. The feature is very useful when you want to use event-driven programming. I hope this helps. Thank you for reading!
I think that it's great how much easier these pump system service naples fl make your life. It really is nice to look at the code of it all and see how it all works.
ReplyDelete