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

如何基于Service Bus Trigger的deliveryCount设置Polly重试延迟

基于ServiceBus Trigger的deliveryCount动态设置Polly重试延迟的实现方案

方案一:函数内部动态生成重试策略

直接在Azure函数方法内,利用拿到的deliveryCount参数生成对应的Polly重试策略,无需在DI阶段提前配置固定策略。

首先将函数改为异步(适配Polly异步策略与HttpClient异步调用),注入IHttpClientFactory,代码示例如下:

[FunctionName("ServiceBusQueueTriggerCSharp")]                    
public static async Task Run(
    [ServiceBusTrigger("myqueue", Connection = "ServiceBusConnection")] 
    string myQueueItem,
    Int32 deliveryCount,
    IHttpClientFactory httpClientFactory,
    ILogger log)
{
    var httpClient = httpClientFactory.CreateClient(ClientNames.HttpClient);
    
    // 根据当前消息的deliveryCount生成重试延迟规则
    var retryPolicy = HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(1, _ => TimeSpan.FromSeconds(5 * deliveryCount)); // 用deliveryCount替代retryAttempt计算延迟

    try
    {
        await retryPolicy.ExecuteAsync(async () => 
        {
            var response = await httpClient.GetAsync("目标API地址");
            response.EnsureSuccessStatusCode();
            return response;
        });
    }
    catch (Exception ex)
    {
        log.LogError(ex, "HTTP调用经重试后仍失败");
        throw; // 抛出异常让ServiceBus按配置处理消息重试
    }
}

方案二:通过Polly Context传递deliveryCount

保留DI中的策略框架,通过Polly的Context对象将deliveryCount动态传递给全局策略,在策略中读取该值计算延迟。

第一步:修改DI中的策略配置

services.AddHttpClient(ClientNames.HttpClient)
    .SetHandlerLifetime(TimeSpan.FromMinutes(5))
    .AddPolicyHandler(GetRetryPolicyWithContext());

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicyWithContext()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(1, (_, context) => 
        {
            // 从Context中读取deliveryCount,读取失败则用默认值兜底
            if (context.TryGetValue("DeliveryCount", out var deliveryCountObj) && deliveryCountObj is int deliveryCount)
            {
                return TimeSpan.FromSeconds(5 * deliveryCount);
            }
            return TimeSpan.FromSeconds(5);
        });
}

第二步:函数中传递Context调用HttpClient

[FunctionName("ServiceBusQueueTriggerCSharp")]                    
public static async Task Run(
    [ServiceBusTrigger("myqueue", Connection = "ServiceBusConnection")] 
    string myQueueItem,
    Int32 deliveryCount,
    IHttpClientFactory httpClientFactory,
    ILogger log)
{
    var httpClient = httpClientFactory.CreateClient(ClientNames.HttpClient);
    // 创建Polly Context并传入deliveryCount
    var pollyContext = new Context { { "DeliveryCount", deliveryCount } };

    try
    {
        // 必须使用SendAsync并传入Context,确保策略能读取到传递的参数
        var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "目标API地址"), pollyContext);
        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        log.LogError(ex, "HTTP调用经重试后仍失败");
        throw;
    }
}

注意事项

  • 两种方案都建议将函数改为异步,避免阻塞Azure函数宿主,同时适配Polly与HttpClient的异步API。
  • 需注意Polly的重试逻辑与ServiceBus自身的消息重试(如MaxDeliveryCount配置)的层级关系,避免重复重试导致不必要的延迟。
  • 方案一更适合无需复用策略结构的场景,实现更直接;方案二更适合需要复用策略逻辑,仅动态调整延迟参数的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 03:15:09