Wednesday, 9 March 2016

Windows Azure Service Bus & Web API a Match Made in Heaven?

 

 
 
 
Rate This

ads_longpollA little while ago the Windows Azure team introduced the message pump pattern to Service Bus Message Bus SDK and it got me thinking about how I could leverage this from any web enabled client.
I wanted to create a long polling REST service that would allow me to extend the message pump pattern over a protected REST service. This is my proof of concept and should not be used in production without a little exploration.
A long poll means that a client makes a request to the server. The server then delays the response until an event occurs. Keep in mind that this is especially useful when you want to communicate events to clients through firewalls. Furthermore, this is a great way to reduce the number of requests made by clients. On the other hand, long poll requests eat up resources, therefore you will need to load test your endpoints in order to identify their limits.

The Message Source

I used the following Windows Form application to push messages to a Windows Azure Service Bus Topic.
9-6-2013 1-58-54 AM
The following code creates a TopicClient, it then pushes a message to the Windows Azure Service Bus Topic and increments a counter.
public partial class Form1 : Form
{
    private readonly TopicClient client;
    private int count;
    public Form1()
    {
        InitializeComponent();
        var connectionString = CloudConfigurationManager.GetSetting("ServiceBusConnectionString");
        var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
        var topicDescription = namespaceManager.GetTopic("alex-topic");
        client = TopicClient.CreateFromConnectionString(connectionString, topicDescription.Path);
    }
    private void button1_Click(object sender, EventArgs e)
    {
        var message = "message " + count;
        client.Send(new BrokeredMessage(message)
        {
            Label = "test"
        });
            
        count ++;
    }
}

The Message Pump REST Service

Using Web API I created an asynchronous REST endpoint. It connects to a topic subscription on aWindows Azure Service Bus namespace and uses the message pump to retrieve Brokered Messages as they arrive. If no messages have been received within 10 seconds of the requests reception, the endpoint responds with a 
No Content (204) Http Status Code.
Implementing the service using Web API might not be the best approach, but it allowed me to easily test this scenario by creating a long poll endpoint.
The ReceiveBatch method is used to request 200 Brokered Messages that arrive within a period of 10 seconds. Then the received messages are concatenated and returned to the client.
public class PumpController : ApiController
{
    public async Task<HttpResponseMessage> Get()
    {
        return await Task.Run(() =>
        {
            var connectionString = CloudConfigurationManager.GetSetting("ServiceBusConnectionString");
            var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
            var topicDescription = namespaceManager.GetTopic("alex-topic");
            var client = SubscriptionClient.CreateFromConnectionString(connectionString,
                                                                        topicDescription.Path,
                                                                        "alex-subscription",
                                                                        ReceiveMode.ReceiveAndDelete);
            var response = new HttpResponseMessage(HttpStatusCode.NoContent);
            var msg = client.ReceiveBatch(200,TimeSpan.FromSeconds(10d));
            if (msg != null)
            {
                var message = msg.Aggregate("",(s, brokeredMessage) => s + 
                                                                       Environment.NewLine + 
                                                                       brokeredMessage.GetBody<string>());
                response = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StringContent(message)
                };
            }
            return response;
        });
    }
}

The Message Pump REST Service Client

9-6-2013 2-13-13 AM
The client is composed of a continuous loop which keeps polling from the service.  As it can be observed from the console application, every time the client queries the service, it receives the messages that were added since the its last request.
To make requests to the REST service I used a RestClient which I previously built using .Net 4.5 and the Enterprise Library Transient Block. You can read all about it in my blog post entitles “Asynchronously Calling REST Services From a Windows Azure Role”.
static void Main(string[] args)
{
    var tokenSource = new CancellationTokenSource();
    var token = tokenSource.Token;
    Task.Run(() =>
    {
        while (!token.IsCancellationRequested)
        {
            Console.WriteLine("called service |> " + DateTime.Now);
            RestClient.Uri("http://localhost:1928/api/pump&quot;)
                    .GetAsync((uri, code, value) => Console.WriteLine(code.ToString()))
                    .ContinueWith(task => Console.WriteLine(task.Result), token)
                    .Wait(token);
        }
    }, token);
    Console.ReadLine();
    tokenSource.Cancel();
}

Final Thoughts

Although this is only a proof of concept, I see some potential because this solution can be load balanced over multiple Web Role instances. The complete flow from the message source to the client felt snappy (on average less than 100 millisecond round trip delays) and I’m quite curious about the maximum load.
How would you implement a long poll enabled REST service?

1 comment:

  1. I’ll immediately grab your rss feed as I can not find your email subscription link or newsletter service. Do you have any? Kindly let me know in order that I could subscribe. Thanks.
    voyance en ligne gratuite

    ReplyDelete

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...