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

Azure Service Bus SendBatchAsync在遗留Web API中超时问题求助

问题

部署在Azure App Services上的遗留Web API,使用WindowsAzure.ServiceBus 7.0.1 NuGet包操作Azure Service Bus。调用PublishMessageBatch批量推送消息至队列时,每次都超时,无消息入队。认证采用AzureActiveDirectoryTokenProvider.AuthenticationCallback。

已尝试的操作:

  • 添加ConfigureAwait(false)排查死锁问题,无效
  • 日志分析:Azure App Service日志流显示API调用返回HTTP 499状态码,客户端2分钟后自动取消请求
  • 托管标识权限配置正确,除SendBatchAsync外其他Service Bus操作正常

日志情况:推送到Kusto集群的最后一条日志为_logger.TraceInfo($"Value of audience: {audience}, authority: {authority} and state {state}");,后续无异常或错误日志输出。

需要解决两个问题:

  1. 如何修改代码让PublishMessageBatch正常运行
  2. WindowsAzure.ServiceBus 7.0.1与Azure App Services是否存在已知超时问题

相关代码片段

public async Task PublishMessageBatch(IEnumerable<BrokeredMessage> queueMessages)
{
    await _logger.ExecuteWithInstrumentationAsync("ServiceBusQueueClient.PublishMessageBatch", string.Empty, async () =>
    {
        _logger.TraceInfo("Pushing message in Queue");
        InitializeIfUnavailable();
        await _sbQueueClient.SendBatchAsync(queueMessages).ConfigureAwait(false);
        return true;
    });
}
public void InitializeIfUnavailable()
{
    Uri serviceBusURI = _queueConnectionString.GetServiceBusURIFromConnectionString();
    string aadAuthority = _configuration.GetValue<string>(CCMConstants.AADAuthorityURL);
    if (_sbQueueClient?.IsClosed != false)
    {
        lock (_lock)
        {
            if (_sbQueueClient?.IsClosed != false)
            {
                
                _logger.TraceInfo("initializing QueueClient AAD");
                var azureAuthCallback = new AzureActiveDirectoryTokenProvider.AuthenticationCallback(GetTokenAsync);
                _sbQueueClient = QueueClient.CreateWithAzureActiveDirectory(serviceBusURI, _queuePath, azureAuthCallback, aadAuthority, ReceiveMode.PeekLock);
                _logger.TraceInfo("QueueClient initialized successfully with AAD");
                _sbQueueClient.RetryPolicy = RetryPolicy.Default;
            }
        }
    }

    if (_sbNamespaceManager == null)
    {
        var azureAuthCallback = new AzureActiveDirectoryTokenProvider.AuthenticationCallback(GetTokenAsync);
        TokenProvider token = TokenProvider.CreateAzureActiveDirectoryTokenProvider(azureAuthCallback, serviceBusURI, aadAuthority);
        _sbNamespaceManager = new NamespaceManager(serviceBusURI, token);
        _logger.TraceInfo("Initialized NamespaceManager for ServiceBus with AAD");
    }
}

private async Task<string> GetTokenAsync(string audience, string authority, object state)
{
    _logger.TraceInfo($"Value of audience: {audience}, authority: {authority} and state {state}");
    return (await (new ManagedIdentityCredential("<client-id>")).GetTokenAsync(new TokenRequestContext(new[] { "https://servicebus.azure.net/.default" }), CancellationToken.None)).Token;
}

解决方案与分析

代码修改建议

  1. 修正令牌受众不匹配问题
    WindowsAzure.ServiceBus 7.0.1的AAD认证回调中,audience参数是当前Service Bus命名空间的URI(如https://your-namespace.servicebus.windows.net/),但现有代码固定使用全局scopehttps://servicebus.azure.net/.default,导致令牌受众与Service Bus要求不匹配,被服务端拒绝后引发超时。修改GetTokenAsync方法:
private async Task<string> GetTokenAsync(string audience, string authority, object state)
{
    _logger.TraceInfo($"Value of audience: {audience}, authority: {authority} and state {state}");
    // 用传入的audience构造符合要求的scope
    var scope = $"{audience.TrimEnd('/')}/.default";
    return (await (new ManagedIdentityCredential("<client-id>")).GetTokenAsync(new TokenRequestContext(new[] { scope }), CancellationToken.None)).Token;
}
  1. 完善初始化逻辑的线程安全
    现有NamespaceManager初始化未加锁,多线程环境下可能重复创建实例引发连接冲突,给该部分添加锁:
public void InitializeIfUnavailable()
{
    Uri serviceBusURI = _queueConnectionString.GetServiceBusURIFromConnectionString();
    string aadAuthority = _configuration.GetValue<string>(CCMConstants.AADAuthorityURL);
    if (_sbQueueClient?.IsClosed != false)
    {
        lock (_lock)
        {
            if (_sbQueueClient?.IsClosed != false)
            {
                _logger.TraceInfo("initializing QueueClient AAD");
                var azureAuthCallback = new AzureActiveDirectoryTokenProvider.AuthenticationCallback(GetTokenAsync);
                _sbQueueClient = QueueClient.CreateWithAzureActiveDirectory(serviceBusURI, _queuePath, azureAuthCallback, aadAuthority, ReceiveMode.PeekLock);
                _logger.TraceInfo("QueueClient initialized successfully with AAD");
                _sbQueueClient.RetryPolicy = RetryPolicy.Default;
            }
        }
    }

    if (_sbNamespaceManager == null)
    {
        lock (_lock) // 添加锁保证线程安全
        {
            if (_sbNamespaceManager == null)
            {
                var azureAuthCallback = new AzureActiveDirectoryTokenProvider.AuthenticationCallback(GetTokenAsync);
                TokenProvider token = TokenProvider.CreateAzureActiveDirectoryTokenProvider(azureAuthCallback, serviceBusURI, aadAuthority);
                _sbNamespaceManager = new NamespaceManager(serviceBusURI, token);
                _logger.TraceInfo("Initialized NamespaceManager for ServiceBus with AAD");
            }
        }
    }
}
  1. 添加超时控制与取消令牌
    给SendBatchAsync添加超时逻辑,避免无限等待,同时捕获超时异常便于排查:
public async Task PublishMessageBatch(IEnumerable<BrokeredMessage> queueMessages, CancellationToken cancellationToken = default)
{
    await _logger.ExecuteWithInstrumentationAsync("ServiceBusQueueClient.PublishMessageBatch", string.Empty, async () =>
    {
        _logger.TraceInfo("Pushing message in Queue");
        InitializeIfUnavailable();
        // 30秒超时,与传入的取消令牌关联
        using var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
        using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
        await _sbQueueClient.SendBatchAsync(queueMessages, linkedTokenSource.Token).ConfigureAwait(false);
        _logger.TraceInfo("Message batch sent successfully");
        return true;
    });
}

WindowsAzure.ServiceBus 7.0.1与Azure App Services的已知问题

WindowsAzure.ServiceBus 7.0.1是2017年左右发布的老旧版本,存在以下与Azure App Services相关的兼容性问题:

  • 该版本默认使用的TLS版本可能低于Azure App Services要求的最低标准(当前要求TLS 1.2+),导致连接被服务端拒绝,引发超时
  • 旧版本的AAD认证实现与Azure App Services托管标识集成存在缺陷,令牌缓存、刷新逻辑不完善,可能导致认证流程卡住
  • 客户端连接池管理逻辑存在漏洞,在Azure App Services多实例环境下易出现连接耗尽,引发超时

优先级建议:如果业务允许,优先升级到最新的Azure.Messaging.ServiceBus包,该包完全支持托管标识,性能、稳定性和兼容性远优于旧版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 10:11:20