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

ServiceBusRetryOptions与SessionProcessor重试策略失效问题

Azure Service Bus Session Processor 重试策略不生效问题解决

问题描述

使用.NET 7 + Azure.Messaging.ServiceBus SDK实现连接Azure Service Bus Topic的会话处理器,尝试通过ServiceBusClientOptions.RetryOptions设置MaxRetries=2来控制消息重试次数,但测试时发现实际重试次数由Azure门户中订阅设置的MaxDeliveryCount(10)决定,抛出异常后消息的DeliveryCount会一直涨到10才停止。需求是遇到内部服务器错误时,无需重新发布消息即可完成指定次数的重试。

相关代码如下:

using Azure.Messaging.ServiceBus;

namespace ServiceBusProcessor;
public class ServiceBusProcessorHandler : BackgroundService
{
    private static readonly string ConnectionString = "";
    private static readonly string TopicName = "";
    private static readonly string SubscriptionName = "";
    private readonly ServiceBusClient serviceBusClient;
    private readonly ServiceBusSessionProcessor serviceBusSessionProcessor;
    public ServiceBusProcessorHandler()
    {
        this.serviceBusClient = new ServiceBusClient(ConnectionString, new ServiceBusClientOptions()
        {
            RetryOptions = new ServiceBusRetryOptions()
            {
                Mode = ServiceBusRetryMode.Exponential,
                MaxRetries = 2,
                MaxDelay = TimeSpan.FromMilliseconds(10000),
                Delay = TimeSpan.FromMilliseconds(1000)
            }
        });
        this.serviceBusSessionProcessor = this.serviceBusClient.CreateSessionProcessor(TopicName, SubscriptionName, new ServiceBusSessionProcessorOptions()
        {
            MaxConcurrentSessions = 100,
            PrefetchCount = 100,
            SessionIdleTimeout = TimeSpan.FromSeconds(1),
        });
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        this.serviceBusSessionProcessor.ProcessMessageAsync += (args) =>
        {
            Console.WriteLine($"DeliveryCount: {args.Message.DeliveryCount}");
            Console.WriteLine(args.Message.Body);
            throw new NotImplementedException("Not Implemented");
        };

        this.serviceBusSessionProcessor.ProcessErrorAsync += (args) =>
        {
            Console.WriteLine(args.Exception);
            return Task.CompletedTask;
        };

        await this.serviceBusSessionProcessor.StartProcessingAsync();
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("Service is stopping.");
        await base.StopAsync(cancellationToken);
    }
}

原因分析

ServiceBusClientOptions.RetryOptions配置的是客户端与Service Bus服务端交互时的重试策略,比如连接建立失败、发送/接收请求超时、服务端返回临时错误(如5xx)等场景的重试,并不控制消息处理失败后的重试次数。

当你在ProcessMessageAsync事件处理程序中抛出异常时,SessionProcessor会自动将消息标记为Abandon,Service Bus服务端会将消息重新放回队列,直到消息的DeliveryCount达到订阅设置的MaxDeliveryCount,之后消息会被转入死信队列。这就是为什么实际重试次数由门户中的MaxDeliveryCount决定。

解决方案

要实现消息处理失败时的本地指定次数重试,需要在消息处理逻辑内部实现重试逻辑,而不是依赖Service Bus服务端的重投递。推荐使用Polly库来简化重试策略的实现,步骤如下:

  1. 安装Polly NuGet包:
Install-Package Polly
  1. 修改消息处理逻辑,添加本地重试:
this.serviceBusSessionProcessor.ProcessMessageAsync += async (args) =>
{
    Console.WriteLine($"DeliveryCount: {args.Message.DeliveryCount}");
    Console.WriteLine(args.Message.Body);

    // 定义重试策略:最多重试2次,仅针对内部服务器错误类异常
    var retryPolicy = Policy
        .Handle<Exception>(ex => ex is NotImplementedException || 
                                (ex.InnerException is HttpRequestException httpEx && 
                                 httpEx.StatusCode == System.Net.HttpStatusCode.InternalServerError))
        .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

    try
    {
        await retryPolicy.ExecuteAsync(async () =>
        {
            // 这里是你的实际业务处理逻辑
            throw new NotImplementedException("Not Implemented");
        });
        // 处理成功,完成消息
        await args.CompleteMessageAsync(args.Message);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"处理失败,已用完本地重试次数: {ex.Message}");
        // 可以选择放弃消息(让服务端重投)或直接死信
        // await args.AbandonMessageAsync(args.Message);
        await args.DeadLetterMessageAsync(args.Message, "处理失败", "本地重试次数已用完");
    }
};

关键说明

  • 本地重试不会增加消息的DeliveryCount,因为重试过程中消息一直被处理器持有,没有调用Abandon或DeadLetter。
  • 当本地重试次数用完后,根据业务需求选择:
    • 调用AbandonMessageAsync:让服务端重新投递消息,此时DeliveryCount会+1,受门户MaxDeliveryCount限制。
    • 调用DeadLetterMessageAsync:直接将消息转入死信队列,不再重试。
    • 调用CompleteMessageAsync:标记消息为完成(不推荐,除非确认无需重试)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:02:06