When my .NET 7 worker service application can not connect to a service bus instance, I want it to error/exit. I see an error in the logs:
[ERR] ErrorHandler invoked with ErrorSource: Receive, FullyQualifiedNamespace: EntityPath, Exception: Azure.Messaging.ServiceBus.ServiceBusException: The requested name is valid, but no data o...
However, no exception is throw to my code, and it just keeps retrying this endlessly instead of exiting:
[WRN] RunOperation encountered an exception and will retry. Exception: Azure.Messaging.ServiceBus.ServiceBusException: The requested name is valid, but no data of the requested type was found. ErrorCode: NoData (ServiceCommunicationProblem).
I can not find where these logs come from, or intercept the exception, presumably from Azure.Messaging.ServiceBus
Question: how can I make my application throw an exception and exit when it can not connect to service bus / when the above happens?
Implementation details
In my application I configure a worker, and my ServiceBusClient in program.cs as follows:
services.AddHostedService<ServiceBusWorker>();
services.AddAzureClients(clientsBuilder =>
{
clientsBuilder.AddServiceBusClient(serviceBusConfiguration?.ConnectionString)
.WithName(serviceBusConfiguration?.MyQueue);
});
Then in my worker I construct as follows::
using Azure.Messaging.ServiceBus;
public ServiceBusWorker(IAzureClientFactory<ServiceBusClient> serviceBusClientFactory)
{
_serviceBusClientFactory = serviceBusClientFactory;
var connectionString = serviceBusConfiguration.Value.ConnectionString;
_requestQueueClient = _serviceBusClientFactory.CreateClient(_requestQueue);
And the worker starts as follows:
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
await using var requestProcessor = _requestQueueClient.CreateProcessor(_requestQueue, _serviceBusProcessorOptions);
// configure the message and error handler to use
requestProcessor.ProcessMessageAsync += ProcessMessageAsync;
requestProcessor.ProcessErrorAsync += ErrorHandler;
await requestProcessor.StartProcessingAsync(cancellationToken);
while (!cancellationToken.IsCancellationRequested) { await Task.Delay(1000, cancellationToken); } //Need to improve. Required to keep the requestProcessor alive for now until better solution.
}
catch (Exception ex)
{
_logger.LogError(ex, "Error when starting the request processor");
throw;
}
}
What I tried
I have tried to configure a retry policy in program.cs as follows, but it doesn't make a difference, I assume because it relates to message retries and not my scenario:
services.AddAzureClients(clientsBuilder =>
{
var serviceBusRetryOptions = new ServiceBusRetryOptions
{
MaxRetries = 3,
Delay = TimeSpan.FromSeconds(2),
TryTimeout = TimeSpan.FromSeconds(30)
};
clientsBuilder
.AddServiceBusClient(serviceBusConfiguration?.ConnectionString)
.ConfigureOptions(options =>
{
options.RetryOptions = serviceBusRetryOptions;
})
.WithName(serviceBusConfiguration?.RequestQueue);
clientsBuilder
.AddServiceBusClient(serviceBusConfiguration?.ConnectionString)
.ConfigureOptions(options =>
{
options.RetryOptions = serviceBusRetryOptions;
})
.WithName(serviceBusConfiguration?.ResponseQueue);
});
You can inject
IHostApplicationLifetimeinto your worker and call_hostApplicationLifetime.StopApplication()to stop your application gracefully.