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

Azure Service Bus问题:AbandonMessageAsync未递增投递计数且日志暴增

Azure Service Bus消息投递计数异常导致函数无限重试问题排查

问题描述

我们使用Azure Functions通过ServiceBusTrigger处理Azure Service Bus队列消息,消息入队时触发函数。单条消息在2.5天内触发了约800万条AppException日志,成本远超预期。怀疑投递计数未正常递增,导致消息无法达到Max Delivery Count进入死信队列,推测AbandonMessageAsync在某些场景下未正常工作。

队列配置详情

  • Lock Duration:1分钟
  • Max Delivery Count:10
  • Message Time to Live:3天

函数简化代码

[Function(nameof(PDFGenFunction))]
public async Task Run(
[ServiceBusTrigger(SourceQueue, Connection = ConnectionStringKey)]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions)
{
    try
    {
        _logger.LogInformation($"Message ID: {message.MessageId}");
        _logger.LogInformation($"PdfGenerationRequest - Received message: {message.Body.ToString()}");
        _logger.LogInformation($"Message Content-Type: {message.ContentType}");

        var outputJSON = JsonConvert.DeserializeObject<OutputJSON>(message.Body.ToString());
        if (outputJSON != null)
        {
            var result = await SendPdfGenerationRequest(message.Body.ToString());
            if(result.Status == PdfResponseStatus.Queued)
            {
                await SendMessageToPdfCompletionQueue(result);
                await messageActions.CompleteMessageAsync(message);
            }
            else
            {
                _logger.LogError($"PdfGenerationRequest - request failed: {result.Urn}, application string: {message.Body.ToString()}");
                await messageActions.AbandonMessageAsync(message);
            }
        }
        else
        {
            _logger.LogError($"PdfGenerationRequest - Invalid JSON string data, application string: {message.Body.ToString()}");
            await messageActions.CompleteMessageAsync(message);
        }
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Error processing application submission: {messageBody}", message.Body.ToString());

        await messageActions.AbandonMessageAsync(message);
    }
}

host.json配置

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      },
      "enableLiveMetricsFilters": true
    }
  },
  "extensions": {
    "queues": {
      "visibilityTimeout": "00:03:00",
      "maxDequeueCount": 5
    }
  }
}

排查与解决建议

  1. 确认投递计数实际变化:通过Azure门户的Service Bus队列监控、Azure CLI或SDK获取目标消息的DeliveryCount属性,验证每次调用AbandonMessageAsync后计数是否递增。若计数未上涨,说明Abandon操作未生效;若计数正常,则需排查重试间隔或配置冲突。
  2. 修正host.json配置冲突:当前extensions.queues节点是针对Azure Storage Queue的配置,对Service Bus完全无效。Service Bus的扩展配置需放在extensions.serviceBus节点下,示例:
    "extensions": {
      "serviceBus": {
        "maxAutoLockRenewalDuration": "00:05:00",
        "messageHandlerOptions": {
          "autoComplete": false,
          "maxConcurrentCalls": 1,
          "maxAutoRenewDuration": "00:05:00"
        }
      }
    }
    
  3. 排查AbandonMessageAsync执行有效性:
    • 在调用AbandonMessageAsync前后添加日志,记录message.DeliveryCount,确认该方法是否被执行及执行前的计数。
    • 捕获AbandonMessageAsync自身的异常:若消息锁已过期,调用Abandon会失败,此时Service Bus会自动解锁消息并重新入队,但投递计数不会递增,导致无限重试。
    • 检查函数执行超时:若函数执行时间超过Lock Duration(1分钟)且未开启自动锁续期,消息锁会过期,后续Abandon操作无效,消息会被立即重试且计数不涨。
  4. 验证PDF生成API超时问题:若SendPdfGenerationRequest调用超时超过1分钟,且未配置锁续期,会导致锁过期后消息立即重试,这正是周末产生海量日志的核心原因——无间隔的无限重试。
  5. 临时缓解措施:
    • 手动将问题消息移入死信队列,终止无限重试。
    • 临时降低函数并发数,减少日志生成速度。
  6. 长期优化方案:
    • 配置Service Bus扩展的自动锁续期,确保函数执行时间超过Lock Duration时锁不会过期。
    • 在代码中捕获AbandonMessageAsync的异常,避免因锁过期导致的操作失败。
    • 给PDF生成API添加超时控制,或优化函数逻辑确保执行时间在锁有效期内。
    • 实现消息幂等性,避免重复处理带来的额外开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 08:51:08