Recently Steve Marx and I spent a few hours working on a best practices document for Windows Azure. As expected, this was a fun and educational experience – plenty of goofing around, but also some really good discussion on things to think about when building applications for Windows Azure. One of the items we discussed is a better approach for sleeping inside the Worker Role when pulling from queues. Rather than defaulting to a retry every 10 seconds we decided that the best approach is to exponentially back-off on your queue reads while capping it with an upper bound.

The primary value of this is to decrease the number of storage transactions when reading from your queue, and therefore reduce both bandwidth and transaction costs.

There are plenty of other good posts on this topic that provide a lot more detailed justification and rationale for this approach:

The logic and approach is deceptively simple and I thought I’d share a really simple, yet effective, example. (Incidentally, credit goes to Steve for very quickly putting together the basis of this really simple example.)

Here’s the code:

   string queueName = "queuetest";

   int minInterval = 1;
   int interval = minInterval;

   int exponent = 2;
   int maxInterval = 60;

   CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
   CloudQueueClient queueClient = account.CreateCloudQueueClient();
   CloudQueue queue = queueClient.GetQueueReference(queueName);
   queue.CreateIfNotExist();

   while (true)
   {
      var msg = queue.GetMessage();
      if (msg != null)
      {
         // do something
         queue.DeleteMessage(msg);
         interval = minInterval;

         Trace.WriteLine(string.Format("Interval reset to {0} seconds", interval));
      }
      else
      {
         Trace.WriteLine(string.Format("Sleep for {0} seconds", interval));
         Thread.Sleep(TimeSpan.FromSeconds(interval));
         interval = Math.Min(maxInterval, interval * exponent);
      }
   }

As I said, really simple. The magic is in the last line where we check to see which is smaller – the maximum interval or the product of the interval and the exponent. At some point the product of the interval and exponent grows larger than the maximum interval, and consequently the interval value is set to the maximum interval.

Here’s the output in the Windows Azure Compute Emulator:

   Sleep for 1 seconds 
   Sleep for 2 seconds 
   Sleep for 4 seconds 
   Sleep for 8 seconds 
   Sleep for 16 seconds 
   Sleep for 32 seconds 
   Sleep for 60 seconds 
   Sleep for 60 seconds 
   ...

Now, the application will continue to sleep until it finds a message in the queue, at which point the interval is reset back to one. To test this I used the Azure Storage Explorer and created a new queue message.

AzureStorageExplorerQueue

Once the message is created the output is as follows:

   Interval reset to 1 seconds 
   Sleep for 1 seconds
   Sleep for 2 seconds
   Sleep for 4 seconds
   Sleep for 8 seconds
   ...

And so forth.

You can find all the source code for this sample in my CappedExponentialBackOff repository on GitHub.

Pretty simple but quite useful. I hope this helps!


  • http://convective.wordpress.com/ Neil Mackenzie

    And then there is always long-polling on Service Bus Queues (and Topics).

    – While waiting for new messages either on a Service Bus queue or subscription, your solution will often be issuing a polling request. Fortunately, the Service Bus offers a long-polling receive operation which maintains a connection to the server until a message arrives on a queue or the specified timeout period has elapsed, whichever occurs first. If a long-polling receive is performed synchronously, it will block the CLR thread pool thread while waiting for a new message, which is not considered optimal. The capacity of the CLR thread pool is generally limited; hence there is good reason to avoid using the thread pool for particularly long-running operations.

    http://windowsazurecat.com/2011/09/best-practices-leveraging-windows-azure-service-bus-brokered-messaging-api/

  • Pingback: Nephology » Cost Saving Design with Azure