如何解决无法将类型“Polly.CircuitBreaker.AsyncCircuitBreaker”隐式转换为“Polly.Policy”
我正在尝试为我的 Rest 客户创建一个组合弹性策略,为此我写了以下内容:
private static Policy circuitBreakerPolicy = Policy
.Handle<TimeoutException>()
.CircuitBreakerAsync(3,TimeSpan.FromSeconds(2));
我收到错误
无法将类型 Polly.CircuitBreaker.AsyncCircuitBreaker
隐式转换为 Polly.Policy
我错过了什么?我在网上查了很多参考资料,但我无法对导致此问题的原因做出足够简洁的解释。
用法:
最终,我想将上面的 CircuitBreaker 策略与 WaitandRetry
策略相结合,但我不知道如何提取组合策略:
(这是有效的)
public static IAsyncPolicy<HttpResponseMessage> CreateResiliencePolicy()
{
var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(180));
var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3,retryAttempt => TimeSpan.FromSeconds(Math.Pow(3,retryAttempt)),(result,timeSpan,context) =>
{
});
return timeoutPolicy.WrapAsync(waitAndRetryPolicy);
}
这就是我想要的(不工作):
public static IAsyncPolicy<HttpResponseMessage> CreateResiliencePolicy()
{
var circuitBreakerPolicy = Policy
.Handle<TimeoutException>()
.CircuitBreakerAsync(3,TimeSpan.FromSeconds(2));
var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3,context) =>
{
});
return circuitBreakerPolicy.WrapAsync(waitAndRetryPolicy);
//I want to do this instead
//public static Policy resilientAsyncStrategy =circuitBreakerPolicy.WrapAsync(waitAndRetryPolicy);
//Then return resilientAsyncStrategy
//return resilientAsyncStrategy;
}
然后使用返回的策略实例为:
public async Task<IEnumerable<PaymentDetailDto>> GetAsync()
{
var items = await resilientAsyncStrategy.ExecuteAsync(async () => await client.GetAsync());
return items;
}
解决方法
Polly 定义了以下四种抽象策略类型:
方法 | 功能 | |
---|---|---|
同步 | Policy |
Policy<TResult> |
异步 | AsyncPolicy |
AsyncPolicy<TResult> |
因此,在您的情况下,circuitBreakerPolicy
应定义如下:
private static AsyncPolicy circuitBreakerPolicy = Policy
.Handle<TimeoutException>()
.CircuitBreakerAsync(3,TimeSpan.FromSeconds(2));
每当您想要组合/链接两个(或多个)策略时,您都应该考虑使用 PolicyWrap
(reference)。请记住,策略链在 escalation way 中工作,这意味着如果内部策略无法处理问题,那么它会将其传播到下一个外部策略。
另请记住,政策应该相互兼容。因此,如果其中一个是异步的,那么另一个也应该是异步的。如果内部返回一些东西,那么外部也应该这样做。
因此,您的 CreateResiliencePolicy
可能如下所示:
public static AsyncPolicy<HttpResponseMessage> CreateResilienceStrategy()
{
var circuitBreakerPolicy = Policy<HttpResponseMessage>
.Handle<TimeoutException>()
.CircuitBreakerAsync(3,TimeSpan.FromSeconds(2));
var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3,retryAttempt => TimeSpan.FromSeconds(Math.Pow(3,retryAttempt)),(result,timeSpan,context) =>
{
});
return Policy.WrapAsync(circuitBreakerPolicy,waitAndRetryPolicy);
}
还请记住,订购很重要:
-
Policy.WrapAsync(circuitBreakerPolicy,waitAndRetryPolicy)
你有一个内部重试和一个外部 CB -
Policy.WrapAsync(waitAndRetryPolicy,circuitBreakerPolicy)
你有一个内部 CB 和一个外部重试
以下两行是等价的:
circuitBreakerPolicy.WrapAsync(waitAndRetryPolicy);
Policy.WrapAsync(circuitBreakerPolicy,waitAndRetryPolicy)
如果您想更改政策的顺序,那么您的策略将以不同的方式运作。如果您想使用 CB 作为内部策略并将重试作为外部策略,那么您应该修改 waitAndRetryPolicy
以处理 BrokenCircuitException
。
几个月前,我整理了一个 sample application,它展示了如何逐步设计您的弹性策略。
更新:添加示例代码
测试重试逻辑
我使用以下控制台应用来测试您的重试策略:
private static HttpClient client = new HttpClient();
public static async Task Main(string[] args)
{
var strategy = CreateResilienceStrategy();
await strategy.ExecuteAsync(async (ct) =>
await client.GetAsync("https://httpstat.us/500",ct),CancellationToken.None);
Console.WriteLine("Finished");
}
public static AsyncPolicy<HttpResponseMessage> CreateResilienceStrategy()
{
var circuitBreakerPolicy = Policy<HttpResponseMessage>
.Handle<TimeoutException>()
.CircuitBreakerAsync(3,TimeSpan.FromSeconds(2),onBreak: (_,__) => Console.WriteLine("Break"),onReset: () => Console.WriteLine("Reset"),onHalfOpen: () => Console.WriteLine("HalfOpen"));
var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3,onRetryAsync: (_,ts,___) =>
{
Console.WriteLine($"Retry,penalty: {ts.Seconds} secs");
return Task.CompletedTask;
});
return Policy.WrapAsync(circuitBreakerPolicy,waitAndRetryPolicy);
}
输出:
Retry,penalty: 3 secs
Retry,penalty: 9 secs
Retry,penalty: 27 secs
Finished
如你所见,
- 它在没有运气的情况下执行了所有重试
- 它没有触发断路器
-
strategy.ExecuteAsync
返回了状态代码为 500 的响应 - 它在 Http 调用后继续工作
测试断路器逻辑
因为 CB 策略设置为针对 TimeoutException
触发,所以我将 client.Timeout
中的 Main
设置为 1 毫秒。因此,应用程序因 TaskCanceledException
崩溃。
这样做是因为 HttpClient 在超时的情况下抛出 TaskCanceledException
而不是 TimeoutException
。如果您使用波利的超时政策,那么您将收到 TimeoutRejectedException
。
所以,这是我修改后的代码,以便能够测试 CB
private static HttpClient client = new HttpClient();
public static async Task Main(string[] args)
{
client.Timeout = TimeSpan.FromMilliseconds(1);
var strategy = CreateResilienceStrategy();
try
{
await strategy.ExecuteAsync(async (ct) =>
await client.GetAsync("https://httpstat.us/500",CancellationToken.None);
Console.WriteLine("Finished");
}
catch (Exception ex)
{
Console.WriteLine("Failed with " + ex.GetType().Name);
}
}
public static AsyncPolicy<HttpResponseMessage> CreateResilienceStrategy()
{
var circuitBreakerPolicy = Policy<HttpResponseMessage>
.Handle<OperationCanceledException>()
.Or<TimeoutRejectedException>()
.CircuitBreakerAsync(1,onHalfOpen: () => Console.WriteLine("HalfOpen"));
var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.Or<OperationCanceledException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3,penalty: {ts.Seconds} secs");
return Task.CompletedTask;
});
return Policy.WrapAsync(waitAndRetryPolicy,circuitBreakerPolicy);
}
修改:
- 将超时设置为 1 毫秒
- 将 CB 的连续失败计数从 3 更改为 1
- 更改链接:重试外部,cb 内部
- 为这两个政策添加了
OperationCanceledException
个条件
输出
Break
Retry,penalty: 3 secs
HalfOpen
Break
Retry,penalty: 9 secs
HalfOpen
Break
Retry,penalty: 27 secs
HalfOpen
Break
Failed with OperationCanceledException
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。