Polly重试策略生效需同时满足精准捕获异常、启用jitter退避、嵌套顺序正确;HTTP 503需用OrResult或HandleTransientHttpError捕获,禁用手写Math.Pow退避,必须绑定命名HttpClient,熔断器半开仅放行1个试探请求,且Handle与OrResult须分开声明。

直接说结论:Polly 重试策略不是“加了就生效”,它必须精准捕获异常、带 jitter 退避、嵌套顺序正确,三者缺一不可。
Handle() 捕不到 503 怎么办
HTTP 请求返回 HttpStatusCode.ServiceUnavailable(503)时,HttpClient 不抛异常,而是正常返回 HttpResponseMessage。只写 Handle<httprequestexception>()</httprequestexception> 完全无效。
- 必须显式判断响应状态:用
OrResult<httpresponsemessage>(r => r.StatusCode == HttpStatusCode.ServiceUnavailable)</httpresponsemessage> - 更推荐一步到位:直接用
HttpPolicyExtensions.HandleTransientHttpError(),它已内置覆盖 408、429、全部 5xx 和HttpRequestException - 若业务还定义 JSON 错误码(如
{"code":500}),需额外接OrResult<httpresponsemessage>(r => r.Content.ReadAsStringAsync().ContinueWith(t => ParseCode(t.Result) == 500))</httpresponsemessage>,注意用ContinueWith避免同步阻塞
WaitAndRetryAsync 手写 Math.Pow 会引发重试风暴
看似标准的指数退避:TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),实际会让所有客户端在第 1、2、4、8 秒整点集中重试,下游压力瞬间翻倍。
- 禁用手写
Math.Pow+new Random():多线程下new Random()可能重复种子,抖动失效 - 应使用 Polly 内置抖动算法:
Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(0.5), retryCount: 3) - 该算法生成随机但有边界的延迟,既防雪崩,又保平均响应时间可控
AddPolicyHandler 不绑定命名 HttpClient 就等于没配
直接 new HttpClient() 或从 DI 容器 resolve 出未注册策略的 IHttpClientFactory 实例,Polly 策略根本不会执行。
- 必须通过
services.AddHttpClient<iorderservice>("order-api")</iorderservice>注册命名客户端 - 再链式调用
.AddPolicyHandler(...)绑定策略 - 业务中通过构造函数注入
IOrderService(而非HttpClient)才能触发策略 - 别在业务方法里手动调用
ExecuteAsync——那等于放弃连接池复用和策略生命周期管理
熔断器半开状态为什么只放行一个请求
半开(Half-Open)状态下,默认只允许 1 个试探请求通过,其余立即失败。这不是限制,而是防止试探洪峰压垮本就脆弱的下游服务。
- 别用
AllowHalfOpenAfter随意放大试探请求数量 - 熔断器必须和重试策略组合使用,且顺序重要:通常先熔断后重试,或用
Policy.WrapAsync显式包装 - 单独配置
CircuitBreakerAsync时,exceptionsAllowedBeforeBreaking应结合真实错误率设为 3–5,而非拍脑袋填 10
最易被忽略的一点:所有策略都作用于 HttpResponseMessage 类型时,Handle 和 OrResult 必须分开声明;一旦混用或漏掉结果判断,503、429 这类“合法失败响应”就彻底逃逸出策略控制范围。


















