如何基于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
相关产品推荐
相关产品推荐

