question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Disabled ServiceBus queue causes fixed retry after 300ms

See original GitHub issue

Library name and version

Azure.Messaging.ServiceBus 7.6.0

Describe the bug

Disabled ServiceBus queue causes the ServiceBus client to retry consuming messages after a fixed retry inverval of ~300ms. If MaxConcurrentCalls is set in a ServiceBusProcessorOptions, it will try connect (and fail) that many times in parallel. This happens regardless of what the retry policy is configured to. In my case this results in a virtually infinite loop and causes the application to hog CPU usage if the queue is disabled.

Expected behavior

I expect the client to adhere to the retry policy and retry according to what the retry policy says if the queue is disabled.

Actual behavior

The client will retry consuming messages after ~300ms if the ServiceBus queue is disabled, regardless of what the retry policy says.

Reproduction Steps

Create a queue and disable it in in Azure ServiceBus, then try consume the messages using this .NET 6 app:

using Azure.Messaging.ServiceBus;

var clientOptions = new ServiceBusClientOptions
{
    RetryOptions = new ServiceBusRetryOptions
    {
        Delay = TimeSpan.FromSeconds(10),
        Mode = ServiceBusRetryMode.Exponential
    }
};
var client = new ServiceBusClient("Endpoint=sb://sb-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=secret", clientOptions);
var processorOptions = new ServiceBusProcessorOptions
{
    MaxConcurrentCalls = 100
};

var processor = client.CreateProcessor("some.queue.name", processorOptions);

processor.ProcessMessageAsync += (_ => Task.CompletedTask);
processor.ProcessErrorAsync += args =>
{
    Console.WriteLine($"ServiceBus adapter error: " + args.Exception.Message);
    return Task.CompletedTask;
};

await processor.StartProcessingAsync();

Console.ReadLine();

The application will spam the following message without a 10 second wait between each try:

ServiceBus adapter error: Messaging entity 'sb://sb-namespace.servicebus.windows.net/some.queue.name' is currently disabled. For more information please see https://aka.ms/ServiceBusExceptions . TrackingId:e5f67fd40bf64f088abb211a8a62ed5f_G12, SystemTracker:gateway7, Timestamp:2022-03-02T13:44:02 (MessagingEntityDisabled)

Environment

.NET SDK (reflecting any global.json):
 Version:   6.0.101
 Commit:    ef49f6213a

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19044
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\6.0.101\

Host (useful for support):
  Version: 6.0.1
  Commit:  3a25a7f1cc

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
jsquirecommented, Mar 3, 2022

In this case, as Josh mentioned, MessagingEntityDisabled is not a retriable exception - which I had initially overlooked. When the service operation encounters the error, it does not implicitly retry and fails. This failure is observed by one of the processor tasks which intercepts the exception and surfaces it to your error handler.

The processor is built to be highly resilient in the face of errors. After notifying the application of the failure by invoking the error handler, the task will continue to try and make forward progress. The processor does not understand enough about the host environment or application to automatically apply a heuristic across error patterns to alter that behavior. Currently, it falls on the application to observe errors in the handler and make determinations about the overall state and whether the processor would not be able to recover.

In this scenario, because the error handler is awaited, your application could choose to introduce a delay, whether globally or per-handler, which would be respected and stop. It may also interpret the pattern of exceptions as fatal for the application and call StopProcessingAsync.

In the simple, per-handler case, this would look something like:

processor.ProcessErrorAsync += async args =>
{
    if (args.Exception is ServiceBusException { Reason: ServiceBusFailureReason.MessagingEntityDisabled })
    {
        await Task.Delay(TimeSpan.FromSeconds(30).ConfigureAwait(false);
    }

    Console.WriteLine($"ServiceBus adapter error: " + args.Exception.Message);
};
0reactions
martinminecommented, Mar 10, 2022

Thanks a lot for the help! I will close this issue as I can deal with this problem in the ProcessErrorAsync as demoed above.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can the Azure Service Bus be delayed before retrying a ...
The Azure Service Bus supports a built-in retry mechanism which makes an abandoned message immediately visible for another read attempt. I'm ...
Read more >
Best practices for improving performance using Azure ...
Describes how to use Service Bus to optimize performance when exchanging brokered messages.
Read more >
Building resilient azure functions with retry policies
When a function fails (throws an exception), the delivery count is incremented by 1, and the message is immediately queued again. Retry Policy ......
Read more >
A Quick Way to Solve the Azure Service Bus Availability ...
A Quick Way to Solve the Azure Service Bus Availability Problem · Introduction · The Queue may be Disabled/Send Disabled/Receive Disabled State.
Read more >
azure-servicebus
Create Service Bus namespaces, queues, topics, and subscriptions, and modify their settings. Send and receive messages within your Service Bus channels. Utilize ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found