重试策略需显式设次数、指数退避和总超时;熔断器须自定义shouldHandle识别业务错误;重试与熔断须用PolicyWrapAsync组合,外熔断内重试;HttpClient超时应设为MaxValue交由Polly控制。
默认的 RetryPolicy 不设超时或重试间隔,容易让请求卡住几秒甚至更久。必须显式控制重试次数、退避方式和总耗时上限。
WaitAndRetryAsync 配合指数退避(如 Backoff.DecorrelatedJitterBackoffV2),避免下游雪崩式重试HttpClient 外层加 CancellationToken,并传给 ExecuteAsync,防止策略内部无限等待TimeSpan.FromMilliseconds(3000) 这类硬性超时,否则网络卡顿时策略会等满所有重试周期HttpRequestException 和 TaskCanceledException 混在一起重试,其实后者大概率是上游已取消,再试没意义CircuitBreakerPolicy 默认只对异常类型生效,HTTP 200 但业务返回 {"code":500} 这类“假成功”不会触发熔断,得手动判断响应内容。
AdvancedCircuitBreakerAsync,配合自定义 shouldHandle 函数,检查 response.IsSuccessStatusCode == false 或解析 JSON 后判断 responseContent.code != 0
HttpClient 实例或每个策略实例独立维护状态,别误以为配置一次就全应用生效failureThreshold 是“失败比例”,不是绝对次数;比如设 0.5,意味着最近 10 次里有 5 次失败才会熔断,不是
BrokenCircuitException,不是静默失败,要确保上层有捕获逻辑,否则可能引发未处理异常崩溃不能简单 new 两个策略然后分别调用——必须用 PolicyWrapAsync 组合,否则熔断器收不到重试后的最终结果,无法准确统计失败率。
circuitBreaker),内层放重试(retry),这样重试过程中的失败都算进熔断统计Policy.WrapAsync(retry, circuitBreaker) 的括号方向,写反会导致编译通过但运行时策略不生效policyWrap.ExecuteAsync(() => httpClient.GetAsync(url)),而不是分别执行两个 ExecuteAsync
FallbackPolicy),它应该放在最外层,兜住熔断和重试都失败的情况直接给 HttpClient 设置 Timeout 会跟 Polly 的重试逻辑打架——比如 HttpClient 内部 10 秒超时,而 Polly 重试 3 次每次等 2 秒,第三次还没发出去就被 HttpClient 自己扔异常了。
HttpClient.Timeout 设为 TimeSpan.MaxValue,把超时控制权完全交给 PollyHttpClient 实例应绑定一个固定的策略实例(推荐用 DI 注入单例策略),不要每次请求都 new 新策略,否则熔断状态无法累积IHttpClientFactory,在 AddHttpClient 里用 AddPolicyHandler 注册策略,它会自动处理生命周期和策略复用HttpRequestException 的 InnerException 可能是 SocketException 或 OperationCanceledException,Polly 默认不展开 InnerException,需手动写 ex.InnerException is TimeoutException 这类判断