🔁 How Azure Service Bus Handles Retries + Dead-Letter Queue (DLQ) Monitor Part - 2
Kiran Rongali

Kiran Rongali @kiranrongali

About: 17 years of experience in designing and developing web, Windows, and API services using Microsoft .NET (C#, ASP.NET Core, MVC, WCF, WPF, ADO.NET), Java, and cloud-native technologies.

Location:
Florida
Joined:
Apr 15, 2025

🔁 How Azure Service Bus Handles Retries + Dead-Letter Queue (DLQ) Monitor Part - 2

Publish Date: May 7
4 0

As posted in How Azure Service Bus Handles Retries Part- 1 , the below post focuses on the retry flow and monitoring the Dead-Letter Queue (DLQ)

Step-by-Step Upgrade
1) Simulate a Failure in Message Processing
Replace your original message processor with logic that randomly fails:

csharp

var processor = client.CreateProcessor(queueName, new ServiceBusProcessorOptions());

processor.ProcessMessageAsync += async args =>
{
    string body = args.Message.Body.ToString();
    Console.WriteLine($"Received: {body}");

    // Simulate a failure randomly
    if (new Random().Next(1, 4) == 1)
    {
        throw new Exception("Simulated processing failure.");
    }

    await args.CompleteMessageAsync(args.Message);
    Console.WriteLine("Message completed successfully.");
};

processor.ProcessErrorAsync += async args =>
{
    Console.WriteLine($" Error Handler: {args.Exception.Message}");
    await Task.CompletedTask;
};
Enter fullscreen mode Exit fullscreen mode

This simulates real-world transient issues.

2) Read from the Dead-Letter Queue (DLQ)
This processor will read messages from the DLQ after they fail too many times:

csharp

Console.WriteLine("Starting Dead-Letter Queue Listener...");

var dlqReceiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions
{
    SubQueue = SubQueue.DeadLetter
});

var deadLetters = await dlqReceiver.ReceiveMessagesAsync(maxMessages: 10, TimeSpan.FromSeconds(5));

if (deadLetters.Count == 0)
{
    Console.WriteLine(" No messages in DLQ.");
}
else
{
    Console.WriteLine($" Found {deadLetters.Count} message(s) in DLQ:");
    foreach (var msg in deadLetters)
    {
        Console.WriteLine($"  ❗ Message: {msg.Body}");
        await dlqReceiver.CompleteMessageAsync(msg); // Mark as handled
    }
}
Enter fullscreen mode Exit fullscreen mode

You can loop this or run it on a timer in a real app.

Test It Out:

Send messages with the original sender

Let the random failure simulate retries

Once the MaxDeliveryCount is hit (default: 10), the message will land in the DLQ

DLQ monitor will read and log them

Optional Improvements:

  • Push DLQ metrics to Application Insights
  • Automatically re-send DLQ messages to retry queue (with delay)
  • Add logging to a file or database

Question:
can we use even driven architecture when the message retry fails?

Answer:
Yes — using event-driven architecture even when message retries fail is not only possible, but it's also one of the best patterns to handle failure gracefully and reactively.

Here’s how it works and why it’s useful:

Using Event-Driven Architecture After Retry Fails

What it means:
Instead of letting failed messages silently die or sit in the DLQ, you can emit an event when a failure happens (after all retries), and other systems can react to that event.

Typical Flow with Retry Failure

Producer --> Queue --> Processor --> Fails N times

Moved to DLQ

Dead-letter handler raises an event → Notifier / Logger / Dashboard / Alert

Examples of Event-Driven Responses After Failure

Image description

How to Implement

  1. Emit Custom Event on DLQ Handler After reading from DLQ:
csharp

foreach (var msg in deadLetters)
{
    var body = msg.Body.ToString();
    Console.WriteLine($" Dead-lettered: {body}");

    // Raise an event (example: publish to another queue or topic)
    var failureEvent = new ServiceBusMessage(JsonSerializer.Serialize(new
    {
        Type = "OrderProcessingFailed",
        OriginalPayload = body,
        Timestamp = DateTime.UtcNow
    }));

    await failureEventSender.SendMessageAsync(failureEvent);

    await dlqReceiver.CompleteMessageAsync(msg);
}
Enter fullscreen mode Exit fullscreen mode

You could publish this to:

Another Service Bus queue or topic

Event Grid

A webhook or REST API

A logging pipeline (e.g., Application Insights, Datadog)

Why This Matters?
Benefits of triggering events after retries fail:

  • Real-time observability of critical failures
  • Prevent silent data loss in DLQ
  • Let multiple teams (notifications, support, analytics) respond independently
  • Enables automatic recovery, fallbacks, or audits

Best Practices:

Image description

Comments 0 total

    Add comment