You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

当C# ServiceBusClient无法连接Service Bus时如何退出应用

问题:.NET 7 Worker Service连接Service Bus失败时如何让应用报错退出

我的.NET 7 Worker Service应用无法连接Service Bus实例时,日志已出现错误:

[ERR] ErrorHandler invoked with ErrorSource: Receive, FullyQualifiedNamespace: EntityPath, Exception: Azure.Messaging.ServiceBus.ServiceBusException: The requested name is valid, but no data o...

但异常未抛入业务代码,应用仅无限重试而不退出:

[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).

无法定位这些日志的来源,也无法拦截该异常(推测来自Azure.Messaging.ServiceBus)。需求是:当无法连接ServiceBus或出现上述场景时,让应用抛出异常并退出。

实现细节

program.cs中Worker与ServiceBusClient配置

services.AddHostedService<ServiceBusWorker>();
services.AddAzureClients(clientsBuilder =>
{
    clientsBuilder.AddServiceBusClient(serviceBusConfiguration?.ConnectionString)
      .WithName(serviceBusConfiguration?.MyQueue);
});

Worker构造函数

using Azure.Messaging.ServiceBus;

public ServiceBusWorker(IAzureClientFactory<ServiceBusClient> serviceBusClientFactory)
{
    _serviceBusClientFactory = serviceBusClientFactory;

    var connectionString = serviceBusConfiguration.Value.ConnectionString;

    _requestQueueClient = _serviceBusClientFactory.CreateClient(_requestQueue);
}

Worker启动逻辑

public async Task StartAsync(CancellationToken cancellationToken)
{
    try
    {
        await using var requestProcessor = _requestQueueClient.CreateProcessor(_requestQueue, _serviceBusProcessorOptions);

        // 配置消息和错误处理程序
        requestProcessor.ProcessMessageAsync += ProcessMessageAsync;
        requestProcessor.ProcessErrorAsync += ErrorHandler;

        await requestProcessor.StartProcessingAsync(cancellationToken);

        while (!cancellationToken.IsCancellationRequested) { await Task.Delay(1000, cancellationToken); } // 临时方案,保持processor存活,后续优化
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "启动请求处理器时出错");
        throw;
    }
}

已尝试的操作

在program.cs中配置重试策略,但无效果,推测该策略针对消息处理重试,而非连接失败场景:

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);
});

解决方案

1. 拦截ProcessErrorAsync事件判断致命错误

Service Bus Processor的ProcessErrorAsync会捕获连接类错误,可在此判断错误类型,若为无法恢复的连接错误则触发应用退出。

修改ErrorHandler方法:

private readonly IHostApplicationLifetime _hostApplicationLifetime;

// 构造函数注入IHostApplicationLifetime
public ServiceBusWorker(IAzureClientFactory<ServiceBusClient> serviceBusClientFactory, 
                        IHostApplicationLifetime hostApplicationLifetime)
{
    _serviceBusClientFactory = serviceBusClientFactory;
    _hostApplicationLifetime = hostApplicationLifetime;
    var connectionString = serviceBusConfiguration.Value.ConnectionString;
    _requestQueueClient = _serviceBusClientFactory.CreateClient(_requestQueue);
}

private async Task ErrorHandler(ProcessErrorEventArgs args)
{
    _logger.LogError(args.Exception, "Service Bus处理错误,来源:{ErrorSource}", args.ErrorSource);

    // 判断是否为无法恢复的连接错误
    if (args.Exception is ServiceBusException sbEx 
        && sbEx.Reason == ServiceBusFailureReason.ServiceCommunicationProblem)
    {
        _logger.LogCritical("无法连接到Service Bus,应用将退出");
        // 触发主机停止,让Worker Service退出
        await _hostApplicationLifetime.StopApplicationAsync();
        return;
    }

    // 其他错误按需处理
}

2. 启动阶段主动验证连接

在启动时主动发起连接验证,而非依赖Processor自动重试,失败时直接触发退出:

public async Task StartAsync(CancellationToken cancellationToken)
{
    try
    {
        // 主动验证Service Bus连接
        await _requestQueueClient.GetQueueRuntimePropertiesAsync(_requestQueue, cancellationToken);
        
        await using var requestProcessor = _requestQueueClient.CreateProcessor(_requestQueue, _serviceBusProcessorOptions);

        requestProcessor.ProcessMessageAsync += ProcessMessageAsync;
        requestProcessor.ProcessErrorAsync += ErrorHandler;

        await requestProcessor.StartProcessingAsync(cancellationToken);

        while (!cancellationToken.IsCancellationRequested) { await Task.Delay(1000, cancellationToken); }
    }
    catch (Exception ex)
    {
        _logger.LogCritical(ex, "启动失败,无法连接到Service Bus");
        await _hostApplicationLifetime.StopApplicationAsync();
        throw;
    }
}

GetQueueRuntimePropertiesAsync会触发实际连接请求,失败时直接抛出异常,此时可捕获并触发应用退出。

3. 关闭Processor自动重试(可选)

若希望Processor遇到连接错误后不再重试,可在创建Processor时配置相关参数:

var _serviceBusProcessorOptions = new ServiceBusProcessorOptions
{
    // 关闭自动锁续期
    MaxAutoLockRenewalDuration = TimeSpan.Zero,
    // 按需设置其他限制
};

更推荐通过ProcessErrorAsync区分临时错误与致命错误后主动退出,避免误杀可恢复的场景。


内容的提问来源于stack exchange,提问作者fourbeatcoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 09:25:54