重试策略怎么配才不卡死请求
默认的
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 次失败才会熔断,不是第 5 次就跳闸 熔断后调用会直接抛
BrokenCircuitException,不是静默失败,要确保上层有捕获逻辑,否则可能引发未处理异常崩溃
如何把重试 + 熔断串成一条链
不能简单 new 两个策略然后分别调用——必须用
PolicyWrapAsync组合,否则熔断器收不到重试后的最终结果,无法准确统计失败率。 顺序很重要:外层放熔断(
circuitBreaker),内层放重试(
retry),这样重试过程中的失败都算进熔断统计 别漏掉
Policy.WrapAsync(retry, circuitBreaker)的括号方向,写反会导致编译通过但运行时策略不生效 组合后调用
policyWrap.ExecuteAsync(() => httpClient.GetAsync(url)),而不是分别执行两个
ExecuteAsync如果还加了降级(
FallbackPolicy),它应该放在最外层,兜住熔断和重试都失败的情况
HttpClient 与 Polly 怎么共存不冲突
直接给
HttpClient设置
Timeout会跟 Polly 的重试逻辑打架——比如 HttpClient 内部 10 秒超时,而 Polly 重试 3 次每次等 2 秒,第三次还没发出去就被 HttpClient 自己扔异常了。 把
HttpClient.Timeout设为
TimeSpan.MaxValue,把超时控制权完全交给 Polly 每个
HttpClient实例应绑定一个固定的策略实例(推荐用 DI 注入单例策略),不要每次请求都 new 新策略,否则熔断状态无法累积 如果用了
IHttpClientFactory,在
AddHttpClient里用
AddPolicyHandler注册策略,它会自动处理生命周期和策略复用 注意
HttpRequestException的 InnerException 可能是
SocketException或
OperationCanceledException,Polly 默认不展开 InnerException,需手动写
ex.InnerException is TimeoutException这类判断 实际最难调的往往是熔断窗口期和失败判定粒度——比如 60 秒滑动窗口里,你希望 10 次失败就熔断,但如果请求本身很慢,这 10 次可能集中在最后 2 秒发生,导致熔断来得又急又猛,下游根本来不及恢复。这时候得结合指标监控,动态调整参数。
