Search code examples
azureazure-storage-queues

Azure's QueueClient.ReceiveMessagesAsync returns when there are no messages


I am using Azure Storage Queues and I noticed that I had high costs even though I don't have a lot of items going through my queue. When I analyzed the metrics, I also noticed high bandwidth on the queues. After some investigation I noticed there is something wrong in my code. I use the following loop:

private async Task ProcessEventsAsync(CancellationToken cancellationToken)
{
  while (!cancellationToken.IsCancellationRequested)
  {
    var messages = await _queueClient.ReceiveMessagesAsync(maxMessages: 10, cancellationToken: cancellationToken).ConfigureAwait(false);
    foreach (var message in messages.Value)
    {
      // Event handling here...
      await _queueClient.DeleteMessageAsync(message.MessageId, message.PopReceipt, cancellationToken: CancellationToken.None).ConfigureAwait(false);
    }
  }
}

It looks like the QueueClient.ReceiveMessagesAsync method also returns when there is no message inside the queue. This results that my code keeps looping and eat a lot of CPU and bandwidth.

I would expect this call to block until there is at least one message in the queue. The documentation has the following description for this method:

Receives one or more messages from the front of the queue.

This suggests that it blocks until at least one message is available. Another option is to poll the queue every few seconds, but I rather not poll the queue. To have a proper response-time I need to poll pretty often.


Solution

  • This isn't how Storage Queues were meant to be used. ReceiveMessagesAsync simply makes an HTTP request to the blob-storage queue every time you call it.

    There is no mechanism in the Azure.Storage.Queues SDK that allows it to act like a message dispatcher.

    If you want this kind of behavior, you should look in to Azure Event Hubs. This is the type of thing it was made for: Listen on a hub, when a message becomes available it fires an event in your service and you process it.

    If you are stuck using Storage Queues, then I highly suggest doing a await Task.Delay(5000, token) between each loop. That will drastically reduce the amount of traffic you are generating and your costs will come way down.