A Comprehensive Guide to Azure Service Bus: Messaging Made Easy with Real-World Examples

Arindam Das
6 min readNov 9, 2024

--

Azure Service Bus is a fully managed enterprise message broker, facilitating reliable messaging across distributed applications and services. In this guide, we’ll explore its key features, the various messaging models it supports, and detailed examples on topics like message filtering, message sessions, message ordering, and deferral.

Image from Google Images

Key Features of Azure Service Bus

Azure Service Bus offers robust messaging capabilities for cloud applications, allowing reliable communication and message-driven architecture. Some of its key features include:

  • Guaranteed Message Delivery: Messages are reliably delivered even during network disruptions.
  • Message Ordering and Sessions: Maintains message order within a session.
  • Publish-Subscribe Model: Supports sending messages to multiple subscribers.
  • Deferral and Dead-lettering: Manages un-processable messages and allows for later retrieval.
  • Geo-Disaster Recovery: Ensures high availability with regional backups.

Service Bus Messaging Models

Azure Service Bus supports two primary messaging models:

  • Point-to-Point Messaging (Queues): Suitable for one-to-one messaging where only one consumer processes each message.
  • Publish-Subscribe Messaging (Topics and Subscriptions): Ideal for one-to-many scenarios, allowing multiple consumers to receive and process messages independently.

Queues

Service Bus Queues are the most straightforward messaging mechanism in Azure Service Bus, working on a first-in, first-out (FIFO) basis. Each message is delivered to only one receiver, making queues ideal for tasks that need to be processed by a single consumer, such as processing orders or logging activity.

Queue Characteristics:

  • Supports message retention for up to 14 days.
  • Transactional messaging allows for batch processing.
  • Dead-letter queue (DLQ) support for un-processable messages.

Topics and Subscriptions

Topics and Subscriptions in Azure Service Bus provide a publish-subscribe model, where messages sent to a topic can be delivered to multiple subscribers independently. Each subscription can apply filtering to specify which messages it receives.

Topic Characteristics:

  • Multiple Subscribers: A topic can have many subscribers.
  • Filter Rules: Subscribers can apply filter rules to receive only relevant messages.
  • Decoupled Communication: Publishers do not need to know the number or identity of subscribers.

Setting Up Azure Service Bus

To use Azure Service Bus, start by creating a namespace within your Azure subscription:

  1. Go to Azure Portal > Create a Resource > Service Bus.
  2. Configure your namespace, which serves as a container for queues and topics.
  3. Choose a pricing tier (Standard or Premium) based on your needs.
  4. Create your queue or topic under the namespace.

Once the namespace is ready, you’ll receive a connection string, which will be used in your application to connect and authenticate with Service Bus.

Service Bus Queue Example in .NET

Here’s an example of creating a Service Bus queue, sending, and receiving messages in .NET:

var connectionString = "<Your Service Bus Connection String>";
var queueName = "orderQueue";
ServiceBusClient client = new ServiceBusClient(connectionString);

// Send Message
ServiceBusSender sender = client.CreateSender(queueName);
await sender.SendMessageAsync(new ServiceBusMessage("Hello, Service Bus!"));

// Receive Message
ServiceBusProcessor processor = client.CreateProcessor(queueName, new ServiceBusProcessorOptions());
processor.ProcessMessageAsync += async args =>
{
Console.WriteLine($"Received: {args.Message.Body}");
await args.CompleteMessageAsync(args.Message);
};
processor.ProcessErrorAsync += async args =>
{
Console.WriteLine($"Error occurred: {args.Exception.Message}");
};
await processor.StartProcessingAsync();

Advanced Concepts in Azure Service Bus

Azure Service Bus offers several advanced features for complex messaging scenarios, including:

Dead-lettering

Dead-letter queues (DLQ) handle messages that cannot be processed, either due to an exceeded retry count, expiration, or other issues. Dead-lettered messages can be reviewed later for inspection or manual handling.

Message Sessions

Message Sessions allow for ordered processing of related messages by grouping them under a Session ID. Only one consumer can process messages in a session at any time, preserving message sequence.

Geo-Disaster Recovery

Azure Service Bus provides Geo-Disaster Recovery for failover across Azure regions, ensuring availability in case of regional outages. This feature is only available in the Premium tier.

Filtering Messages on Subscriptions

Each subscription can apply custom filters, so subscribers only receive messages that meet specific criteria, enhancing efficiency and reducing unnecessary processing.

Types of Filters

  1. SQL Filters: Uses SQL-like syntax for complex conditions (e.g., “Priority = ‘High’”).
  2. Correlation Filters: Matches messages based on specific property values, ideal for simple conditions.

Example: Creating Subscription Filters

In this example, we create a filter that allows only high-priority messages to be delivered to the subscription:

var adminClient = new ServiceBusAdministrationClient(connectionString);
await adminClient.CreateSubscriptionAsync(topicName, "HighPriorityNotifications");
var highPriorityFilter = new SqlRuleFilter("Priority = 'High'");
await adminClient.CreateRuleAsync(topicName, "HighPriorityNotifications", new CreateRuleOptions { Filter = highPriorityFilter });

Message Sessions and Ordered Processing

For scenarios requiring message order preservation, Message Sessions ensure that messages are processed in the sequence they were sent. This is especially useful in workflows where related messages, such as order steps, must be processed sequentially.

Ordered Processing Example with Sessions

Messages in a session share a SessionId, which ensures they are received in order by a single consumer.

Handling Out-of-Order Messages with Deferral

If messages arrive out of order, deferring them allows us to keep them in the queue until they can be processed in the correct sequence.

Deferring Out-of-Order Messages Example

In the example below, if messages arrive out of sequence, they are deferred using DeferAsync() and then retrieved in the correct order when possible.

ServiceBusSessionProcessor sessionProcessor = client.CreateSessionProcessor(queueName, new ServiceBusSessionProcessorOptions());
int expectedSequence = 1;
Dictionary<int, ServiceBusReceivedMessage> deferredMessages = new Dictionary<int, ServiceBusReceivedMessage>();

sessionProcessor.ProcessMessageAsync += async args =>
{
int messageSequence = args.Message.ApplicationProperties.TryGetValue("Sequence", out object value) ? (int)value : 0;

if (messageSequence == expectedSequence)
{
Console.WriteLine($"Processing Order {messageSequence}");
expectedSequence++;
await args.CompleteMessageAsync(args.Message);

while (deferredMessages.ContainsKey(expectedSequence))
{
var deferredMessage = deferredMessages[expectedSequence];
Console.WriteLine($"Processing deferred Order {expectedSequence}");
await args.CompleteMessageAsync(deferredMessage);
deferredMessages.Remove(expectedSequence);
expectedSequence++;
}
}
else
{
Console.WriteLine($"Deferring Order {messageSequence}, expected {expectedSequence}");
deferredMessages[messageSequence] = args.Message;
await args.DeferMessageAsync(args.Message);
}
};

await sessionProcessor.StartProcessingAsync();

Use Cases for Azure Service Bus

Azure Service Bus is suitable for a wide range of scenarios:

  • Order Processing: Process orders in sequence, with sessions preserving message order.
  • Broadcast Notifications: Publish alerts to multiple subscribers.
  • Workflow Orchestration: Manage long-running workflows where messages need to be delivered in order.
  • Retry Logic: Retry processing of messages using dead-lettering and deferred messages for error handling.

End-to-End Example in C#

This full example shows how to create a topic with filters, process messages in a session, and handle out-of-order messages with deferral.

var connectionString = "<Your Service Bus Connection String>";
var topicName = "OrderProcessingTopic";
var queueName = "OrderProcessingQueue";
ServiceBusClient client = new ServiceBusClient(connectionString);
ServiceBusAdministrationClient adminClient = new ServiceBusAdministrationClient(connectionString);

// 1. Create Topic and Subscriptions with Filters
await adminClient.CreateTopicAsync(topicName);
await adminClient.CreateSubscriptionAsync(topicName, "HighPriorityNotifications");
var highPriorityFilter = new SqlRuleFilter("Priority = 'High'");
await adminClient.CreateRuleAsync(topicName, "HighPriorityNotifications", new CreateRuleOptions { Filter = highPriorityFilter });

// 2. Send Messages with Session ID and Sequence Property
ServiceBusSender sender = client.CreateSender(topicName);
await sender.SendMessageAsync(new ServiceBusMessage("Order 1") { SessionId = "OrderProcessingSession", ApplicationProperties = { ["Sequence"] = 1, ["Priority"] = "High" } });
await sender.SendMessageAsync(new ServiceBusMessage("Order 2") { SessionId = "OrderProcessingSession", ApplicationProperties = { ["Sequence"] = 2, ["Priority"] = "High" } });
await sender.SendMessageAsync(new ServiceBusMessage("Order 3") { SessionId = "OrderProcessingSession", ApplicationProperties = { ["Sequence"] = 3, ["Priority"] = "High" } });

// 3. Process Messages with Ordered Sequence and Deferral for Out-of-Order
ServiceBusSessionProcessor sessionProcessor = client.CreateSessionProcessor(queueName, new ServiceBusSessionProcessorOptions());
int expectedSequence = 1;
Dictionary<int, ServiceBusReceivedMessage> deferredMessages = new Dictionary<int, ServiceBusReceivedMessage>();

sessionProcessor.ProcessMessageAsync += async args =>
{
int messageSequence = args.Message.ApplicationProperties.TryGetValue("Sequence", out object value) ? (int)value : 0;

if (messageSequence == expectedSequence)
{
Console.WriteLine($"Processing Order {messageSequence}");
expectedSequence++;
await args.CompleteMessageAsync(args.Message);

while (deferredMessages.ContainsKey(expectedSequence))
{
var deferredMessage = deferredMessages[expectedSequence];
Console.WriteLine($"Processing deferred Order {expectedSequence}");
await args.CompleteMessageAsync(deferredMessage);
deferredMessages.Remove(expectedSequence);
expectedSequence++;
}
}
else
{
deferredMessages[messageSequence] = args.Message;
await args.DeferMessageAsync(args.Message);
}
};

await sessionProcessor.StartProcessingAsync();

Conclusion

Azure Service Bus offers extensive capabilities for designing reliable, efficient, and ordered messaging architectures. By combining features like message filtering, sessions, and deferral, developers can address complex scenarios such as ordered message processing and selective message delivery.

--

--

Arindam Das
Arindam Das

No responses yet