gpt4 book ai didi

c# - 无法将类型 'Polly.CircuitBreaker.AsyncCircuitBreaker' 隐式转换为 'Polly.Policy'

转载 作者:行者123 更新时间:2023-12-04 07:23:50 25 4
gpt4 key购买 nike

我正在尝试为我的 Rest 客户创建一个综合弹性策略,为此我编写了以下内容:

private static Policy circuitBreakerPolicy = Policy
.Handle<TimeoutException>()
.CircuitBreakerAsync(3, TimeSpan.FromSeconds(2));

我得到了错误

Cannot implicitly convert type Polly.CircuitBreaker.AsyncCircuitBreaker to 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, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)),
(result, timeSpan, 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 类型:

<表类="s-表"><头><日> 方法函数<正文>同步 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);
}

另请记住,顺序很重要:

  1. Policy.WrapAsync(circuitBreakerPolicy, waitAndRetryPolicy)你有一个内部重试和一个外部 CB
  2. 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, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)),
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 .如果您使用 polly 的超时策略,那么您将收到 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", ct)
, 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, TimeSpan.FromSeconds(2),
onBreak: (_, __) => Console.WriteLine("Break"),
onReset: () => Console.WriteLine("Reset"),
onHalfOpen: () => Console.WriteLine("HalfOpen"));

var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.Or<OperationCanceledException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)),
onRetryAsync: (_, ts, ___) =>
{
Console.WriteLine($"Retry, 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

关于c# - 无法将类型 'Polly.CircuitBreaker.AsyncCircuitBreaker' 隐式转换为 'Polly.Policy',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68333247/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com