Featured image of post Azure Storage Queues in a Nutshell

Azure Storage Queues in a Nutshell

Azure Storage Queues in a Nutshell – With Code Examples

Azure Storage Queues in a Nutshell – With Code Examples

Ever feel like your app is a little too eager to do everything at once? Like a toddler who drank a double espresso?

That’s where Azure Storage Queues come in. They’re like the chill older sibling who says, “Hey, let’s handle this one thing at a time.”


🚀 What Are Azure Storage Queues?

Azure Storage Queues are part of the Azure Storage Account family and provide simple, reliable message queueing for massive scale.

✅ Key Concepts

  • Message: A string (up to 64 KB) you put in the queue.
  • Queue: A storage container for messages.
  • Producer: Sends messages to the queue.
  • Consumer: Pulls messages from the queue and processes them.

Use cases include:

  • Decoupling front-end and back-end processes
  • Asynchronous task processing
  • Load leveling during spikes
  • Retry and resiliency mechanisms

🧪 Getting Started – Prerequisites

You’ll need:

  • An Azure Storage Account
  • .NET 6+ SDK (though older versions will also work fine)
  • NuGet package: Azure.Storage.Queues

Install it with:

1
dotnet add package Azure.Storage.Queues

🎯 Creating and Sending Messages

Here’s how to create a queue and send a message.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
using Azure.Storage.Queues;
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        string connectionString = "DefaultEndpointsProtocol=https;AccountName=youraccount;AccountKey=yourkey;";
        string queueName = "orders";

        QueueClient queueClient = new QueueClient(connectionString, queueName);
        await queueClient.CreateIfNotExistsAsync();

        if (queueClient.Exists())
        {
            string message = "New Order: #1234";
            await queueClient.SendMessageAsync(message);
            Console.WriteLine("Message sent!");
        }
    }
}

Boom! You’ve got a message in your queue.


📥 Receiving Messages

Now let’s receive and process that message:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var receivedMessage = await queueClient.ReceiveMessageAsync();

if (receivedMessage.Value != null)
{
    Console.WriteLine($"Received: {receivedMessage.Value.MessageText}");

    // Delete after processing
    await queueClient.DeleteMessageAsync(
        receivedMessage.Value.MessageId,
        receivedMessage.Value.PopReceipt);
}

Important: If you don’t delete the message, it will reappear after a visibility timeout!


⏳ Message Lifecycle and Visibility Timeout

When a message is read, it becomes invisible for a default time (30 seconds). This prevents other consumers from processing the same message.

You can customize this:

1
await queueClient.SendMessageAsync("Hello!", TimeSpan.FromMinutes(2)); // Delay visibility

Or when retrieving:

1
await queueClient.ReceiveMessageAsync(TimeSpan.FromSeconds(45)); // Keep it hidden longer

🔄 Updating Messages (Bonus Trick)

You can also update a message’s content without removing it:

1
2
3
4
5
await queueClient.UpdateMessageAsync(
    messageId: msg.MessageId,
    popReceipt: msg.PopReceipt,
    messageText: "Updated Content",
    visibilityTimeout: TimeSpan.FromSeconds(10));

Useful for retry logic or marking the message with progress.


⚠️ Handling Poison Messages

If something keeps failing (e.g. bad data), you don’t want it retrying forever.

Use a Dequeue Count check:

1
2
3
4
5
if (msg.DequeueCount > 5)
{
    Console.WriteLine("Poison message detected!");
    // Send to dead-letter queue or alert
}

There’s no native dead-letter queue in Storage Queues (unlike Service Bus), so you’ll have to roll your own.


🛠️ Queue Management

Need to peek at messages without dequeuing?

1
2
var peeked = await queueClient.PeekMessageAsync();
Console.WriteLine($"Peeked: {peeked.Value.MessageText}");

Check the number of messages waiting:

1
2
var props = await queueClient.GetPropertiesAsync();
Console.WriteLine($"Approximate message count: {props.Value.ApproximateMessagesCount}");

Delete the entire queue when you’re done:

1
await queueClient.DeleteIfExistsAsync();

🧵 Parallel Processing with Multiple Consumers

Have multiple workers pull from the queue to speed things up:

1
2
3
4
5
6
7
8
9
Parallel.For(0, 5, async i =>
{
    var message = await queueClient.ReceiveMessageAsync();
    if (message.Value != null)
    {
        Console.WriteLine($"Worker {i} got: {message.Value.MessageText}");
        await queueClient.DeleteMessageAsync(message.Value.MessageId, message.Value.PopReceipt);
    }
});

This is an easy way to scale horizontally when you’ve got lots of messages flying around.


🆚 Storage Queues vs. Service Bus Queues

FeatureStorage QueueService Bus Queue
Max message size64 KB256 KB (Standard), 1 MB (Premium)
Dead-letter support❌ Manual✅ Built-in
FIFO guarantees❌ (best effort)
Delivery semanticsAt least onceAt least once / Exactly once
ProtocolHTTP/HTTPSAMQP, HTTPS
CostCheaperMore features, higher cost

If you’re building something mission-critical with strict ordering and dead-letter needs, go with Service Bus.

But if you want cheap, fast, and simple — Storage Queues are your best friend.


🧽 Wrapping It Up

Azure Storage Queues are a lightweight, cost-effective way to handle asynchronous workflows, decouple components, and handle high loads gracefully.

They’re the duct tape of distributed systems — not always flashy, but incredibly useful.


🧠 Key Ideas Summary

Key IdeaSummary
WhatSimple cloud queueing service from Azure
Use CasesDecoupling, background processing, async messaging
Language SupportWorks with .NET, Python, Node.js, Java, etc.
FeaturesMessage TTL, peek, update, delete, visibility timeout
Storage vs Service BusChoose based on complexity, cost, and features needed