Polly构建弹性策略时AsyncCircuitBreaker转Policy类型错误如何解决
问题根源
- 类型不匹配:Polly的策略分为同步
Policy/ISyncPolicy和异步IAsyncPolicy两大分支,异步方法返回的异步策略不能赋值给同步基类Policy。同时你的重试策略是带返回值的泛型IAsyncPolicy<HttpResponseMessage>,最初声明的熔断策略是无返回值的非泛型IAsyncPolicy,两种泛型参数不同的策略无法直接组合。 - 策略处理条件不对齐:熔断策略仅处理
TimeoutException,没有覆盖重试策略处理的HttpRequestException和500状态码响应,会导致部分异常不会触发熔断逻辑。 - 策略组合顺序错误:
WrapAsync的规则是外层策略调用该方法传入内层策略,常规弹性链路的执行顺序应为超时→重试→熔断,顺序错误会导致熔断逻辑不生效。
修复方案
1. 调整熔断策略声明
对齐重试策略的处理条件,声明为同类型的泛型异步策略:
var circuitBreakerPolicy = Policy .Handle<TimeoutException>() .Or<HttpRequestException>() .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError) .CircuitBreakerAsync(3, TimeSpan.FromSeconds(2));
2. 修正策略组合逻辑与类型声明
全局静态策略不要用Policy类型,改为对应的异步泛型类型IAsyncPolicy<HttpResponseMessage>,同时调整Wrap顺序:
// 全局静态组合策略声明 public static IAsyncPolicy<HttpResponseMessage> ResilientAsyncStrategy; public static IAsyncPolicy<HttpResponseMessage> CreateResiliencePolicy() { // 超时策略也要对齐泛型类型 var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(180)); var circuitBreakerPolicy = Policy .Handle<TimeoutException>() .Or<HttpRequestException>() .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError) .CircuitBreakerAsync(3, TimeSpan.FromSeconds(2)); var waitAndRetryPolicy = Polly.Policy .Handle<HttpRequestException>() .Or<TimeoutException>() .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError) .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)), (result, timeSpan, context) => { }); // 组合顺序:超时(最外层)→ 重试 → 熔断(最内层) ResilientAsyncStrategy = timeoutPolicy.WrapAsync(waitAndRetryPolicy).WrapAsync(circuitBreakerPolicy); return ResilientAsyncStrategy; }
3. 调整调用逻辑
策略执行返回的是HttpResponseMessage,需要补充反序列化为DTO的逻辑:
public async Task<IEnumerable<PaymentDetailDto>> GetAsync() { var response = await ResilientAsyncStrategy.ExecuteAsync(async () => await client.GetAsync()); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<IEnumerable<PaymentDetailDto>>(); }
内容的提问来源于stack exchange,提问作者Golide
相关产品推荐
相关产品推荐

