Home / .NET / Don’t spoil your Thanksgiving sales with naive Azure Service Bus client code

Don’t spoil your Thanksgiving sales with naive Azure Service Bus client code

Edit: The initial title was: “Naive receiving of messages on Azure Service Bus destroys Thanksgiving sales” I changed it because I don’t want to imply that Azure Service Bus as a service is not behaving correctly. Sorry if this cause any inconvenience. 

The Azure Service Bus SDK provides a lot of very smart functionality to build robust libraries, frameworks and application code on top of Azure Service Bus. In the most simplistic scenario, you write code like

var receiveClient = QueueClient.CreateFromConnectionString(connectionString, queueName, ReceiveMode.PeekLock);
receiveClient.OnMessageAsync(async message =>
{
   // do something with the message
   await message.CompleteAsync().ConfigureAwait(false);
},
new OnMessageOptions { AutoComplete = false, MaxConcurrentCalls = 1 })

This code instructs the SDK to push messages into your code passed into OnMessagesAsync as soon as they are available with a maximum concurrency of one, meaning that your delegate will be executed at maximum once concurrently. So if more messages are available in the queue, the OnMessageAsync delegate will only be called when a previous push of a message is over. Since AutoComplete is set to false it is the responsibility of the delegate implementation to call CompleteAsync (completes the messages) or AbandonAsync (puts the message back into the queue) on the message. The code sample shown here uses the PeekLock mode. In the PeekLock mode, the client sends a request to the server to receive a message and sends another request to complete the message. During the lock duration (can be configured) the message is not visible to other clients connected to the same queue. It might become visible again if a client fails to complete or abandon the message in the given PeekLock duration. For our simplistic sample above we already need to know quite a bit. Assuming the delegate would take one second to execute in our code above we could handle a message every second only. This means we have a throughput of one message per second (1 msg/s).

Imagine the receive client would consume our Thanksgiving special sales order queue and our customers would send in 2000 orders per second (yeah our imaginary products are that amazing 😉 ). In one minute of our special Thanksgiving sale, we would receive 120000 orders, but we would be able to consume 60 orders only. To catch up with those 120K orders, it would require us roughly 33 hours to catch up with the orders we received in one minute! Now imagine we’d have a lucky Thanksgiving rush and actually sell products at that rate for ten minutes. We would need almost 24 days to process these orders. I’m sure this code wouldn’t please our bosses and certainly not our imaginary customers!

With our snail orders we’d probably loose all of them and get really bad reviews online. We can do better for sure but that is a topic of the next post.