Polly v8仅针对特定状态码重试失效问题咨询
问题描述
使用Polly v8和.NET Framework 4.7.2,希望仅针对特定HTTP状态码(比如InternalServerError)执行重试,但仅用HandleResult时重试不触发。添加Handle<HttpRequestException>能生效,但会对更多状态码重试,不符合快速失败并记录日志的需求。
示例代码:
public ResiliencePipelineBuilder<HttpResponseMessage> BuildStrategy() { var statusCodes = new List<HttpStatusCode> { HttpStatusCode.InternalServerError }; PredicateBuilder<HttpResponseMessage> predicateBuilder = new PredicateBuilder<HttpResponseMessage>() // .Handle<HttpRequestException>() NOTE: this would work see explanation .HandleResult(response => statusCodes.Contains(response.StatusCode)); ... return new ResiliencePipelineBuilder<HttpResponseMessage>() .AddRetry(new RetryStrategyOptions<HttpResponseMessage>() { ShouldHandle = predicateBuilder, ... }); } public async Task<Data> SendIt() { var strategy = BuildStrategy(); var result = strategy.ExecuteAsync(async token => { var response = await client.SendAsync(...); response.EnsureSuccessStatusCode(); ... }); }
请问能否单独使用v8风格的HandleResult来捕获需要的请求?是否必须回退到v7的实现方式?Polly文档中同时展示了Handle和HandleResult两种方式,但多以成对形式出现。
解决方案
完全可以单独用Polly v8的HandleResult实现仅针对特定状态码的重试,问题出在你的代码逻辑上:
你在ExecuteAsync的委托里调用了response.EnsureSuccessStatusCode(),这个方法会在响应状态码不是2xx成功码时直接抛出HttpRequestException。而你的重试策略只监听HttpResponseMessage类型的返回结果,异常抛出后委托根本不会返回结果,HandleResult的条件自然永远不会触发。
有两种调整方案:
- 方案一:移除
response.EnsureSuccessStatusCode(),直接返回响应结果
让重试策略能检查返回的HttpResponseMessage状态码,等重试逻辑执行完后,再处理成功响应或失败后的日志与异常:
public async Task<Data> SendIt() { var strategy = BuildStrategy(); var response = await strategy.ExecuteAsync(async token => { return await client.SendAsync(...); }); // 非目标重试状态码,按正常逻辑处理 if (!statusCodes.Contains(response.StatusCode)) { response.EnsureSuccessStatusCode(); // 解析响应数据 return ParseResponseData(response); } // 重试后仍失败,记录日志并抛出异常 logger.LogError("请求多次重试后失败,状态码:{StatusCode}", response.StatusCode); throw new HttpRequestException("请求失败", null, response.StatusCode); }
- 方案二:精准捕获
HttpRequestException中的目标状态码
如果不想移除EnsureSuccessStatusCode(),可以在重试策略中处理HttpRequestException,但只针对你指定的状态码触发重试:
PredicateBuilder<HttpResponseMessage> predicateBuilder = new PredicateBuilder<HttpResponseMessage>() .Handle<HttpRequestException>(ex => { return ex.StatusCode.HasValue && statusCodes.Contains(ex.StatusCode.Value); });
这两种方式都完全基于Polly v8的API实现,不需要回退到v7版本。
内容的提问来源于stack exchange,提问作者Keiron
相关产品推荐
相关产品推荐

