Isaac.

Azure Service Bus Messaging

Implement asynchronous messaging with Azure Service Bus.

By EMEPublished: February 20, 2025
azureservice busmessagingasyncqueuestopics

A Simple Analogy

Azure Service Bus is like the postal system for cloud applications. Messages are reliably delivered even if the recipient is temporarily unavailable.


Why Service Bus?

  • Decoupling: Apps don't call each other directly
  • Asynchronous: Don't wait for responses
  • Reliable: Messages persist if app is down
  • Scalable: Handle message spikes
  • Ordering: Optional FIFO guarantees

Queue Operations

using Azure.Messaging.ServiceBus;

var connectionString = "Endpoint=sb://...";
var client = new ServiceBusClient(connectionString);

// Send message
var sender = client.CreateSender("order-queue");

var message = new ServiceBusMessage("Order #123 created")
{
    ContentType = "application/json",
    Subject = "OrderCreated",
    CorrelationId = "order-123"
};

await sender.SendMessageAsync(message);

// Receive messages
var receiver = client.CreateReceiver("order-queue");

var receivedMessage = await receiver.ReceiveMessageAsync();
if (receivedMessage != null)
{
    Console.WriteLine(receivedMessage.Body);
    await receiver.CompleteMessageAsync(receivedMessage);
}

Topics and Subscriptions

// Publish to topic
var topicClient = client.CreateSender("orders-topic");

var message = new ServiceBusMessage("Order #123 created")
{
    ApplicationProperties = { { "Type", "OrderCreated" } }
};

await topicClient.SendMessageAsync(message);

// Subscribe to topic
var receiver = client.CreateReceiver("orders-topic", "email-subscription");

var message = await receiver.ReceiveMessageAsync();
if (message != null)
{
    Console.WriteLine("Email notification triggered");
    await receiver.CompleteMessageAsync(message);
}

Message Processing

public class OrderProcessor
{
    private readonly ServiceBusClient _client;
    
    public async Task StartProcessingAsync()
    {
        var receiver = _client.CreateReceiver("orders-queue");
        
        var options = new ServiceBusProcessorOptions
        {
            MaxConcurrentCalls = 10,
            AutoCompleteMessages = false
        };
        
        var processor = _client.CreateProcessor("orders-queue", options);
        
        processor.ProcessMessageAsync += MessageHandler;
        processor.ProcessErrorAsync += ErrorHandler;
        
        await processor.StartProcessingAsync();
    }
    
    private async Task MessageHandler(ProcessMessageEventArgs args)
    {
        try
        {
            var message = args.Message;
            var body = message.Body.ToString();
            
            // Process message
            await ProcessOrderAsync(body);
            
            // Complete message
            await args.CompleteMessageAsync(message);
        }
        catch (Exception ex)
        {
            // Dead letter on error
            await args.DeadLetterMessageAsync(args.Message);
        }
    }
    
    private Task ErrorHandler(ProcessErrorEventArgs args)
    {
        Console.WriteLine($"Error: {args.Exception}");
        return Task.CompletedTask;
    }
}

Dead Letter Queue

// Messages automatically go to dead letter queue after max retries
var receiver = client.CreateReceiver("orders-queue");

// Access dead letter messages
var deadLetterReceiver = client.CreateReceiver(
    "orders-queue",
    new ServiceBusReceiverOptions { SubQueue = SubQueue.DeadLetter });

var deadLetterMessage = await deadLetterReceiver.ReceiveMessageAsync();

Console.WriteLine($"Reason: {deadLetterMessage.DeadLetterReason}");
Console.WriteLine($"Error: {deadLetterMessage.DeadLetterErrorDescription}");

Best Practices

  1. Use sessions: For correlated messages
  2. Set TTL: Messages expire
  3. Partition keys: Enable message ordering
  4. Dead letter: Handle poison messages
  5. Monitor: Track queue depth

Related Concepts

  • Event Grid
  • Event Hubs
  • Logic Apps
  • Message-driven architecture

Summary

Azure Service Bus provides reliable, scalable messaging for decoupled applications. Use queues for point-to-point and topics for pub/sub patterns.