如何解决在 .Net Core 中捕获 Polly 中的最后一个异常?
我正在使用 Polly (Microsoft.Extensions.Http.Polly
) 和 .net core 的这种配置(使用无效的 URL,用于测试):
private static void RegisterServices()
{
var collection = new ServiceCollection();
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(2); // Timeout for an individual try
collection.AddHttpClient<INetworkService,NetworkService>(url=>
{
url.BaseAddress = new Uri("http://www.google.com:81"); //test bad url
})
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(timeoutPolicy); ;
_serviceProvider = collection.BuildServiceProvider();
}
GetRetryPolicy
在哪里:
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode != HttpStatusCode.OK)
.Or<TimeoutRejectedException>()
.Or<TaskCanceledException>()
.Or<OperationCanceledException>()
.WaitAndRetryAsync(3,retryAttempt =>
{
return TimeSpan.FromSeconds(2);
},onRetry: (response,delay,retryCount,context) =>
{
Console.WriteLine($"______PollyAttempt_____ retryCount:{retryCount} ");
});
}
输出是:
_PollyAttempt retryCount:1
_PollyAttempt retryCount:2
_PollyAttempt retryCount:3
异常:(TimeoutException) 通过 TimeoutPolicy 异步执行的委托没有在超时时间内完成。
我想在上次尝试失败后发送一封电子邮件。
问题:
我怎样才能捕捉到那个最终异常?是否有任何内置机制可以让我知道 Polly 失败了?
(我目前的工作代码:https://pastebin.pl/view/a2566d51)
解决方法
让我们从一个根本不使用 Polly 的简单设置开始:
private static void RegisterServices()
{
var collection = new ServiceCollection();
collection.AddHttpClient<INetworkService,NetworkService>(sonol =>
{
sonol.BaseAddress = new Uri("http://www.google.com:81");
});
_serviceProvider = collection.BuildServiceProvider();
}
- 100 秒(HttpClient 的默认超时)后,它将失败并显示
TaskCanceledException
。换句话说,HttpClient 取消了请求,因为它没有收到任何响应。
现在让我们稍微改变一下 HttpClient 设置:
private static void RegisterServices()
{
var collection = new ServiceCollection();
collection.AddHttpClient<INetworkService,NetworkService>(sonol =>
{
sonol.Timeout = TimeSpan.FromSeconds(3); // << NEW CODE
sonol.BaseAddress = new Uri("http://www.google.com:81");
});
_serviceProvider = collection.BuildServiceProvider();
}
- 3 秒后 HttpClient 取消请求并抛出
TaskCanceledException
现在,注释掉这个超时设置,让我们设置超时策略:
private static void RegisterServices()
{
var collection = new ServiceCollection();
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(2);
collection.AddHttpClient<INetworkService,NetworkService>(sonol =>
{
//sonol.Timeout = TimeSpan.FromSeconds(3);
sonol.BaseAddress = new Uri("http://www.google.com:81");
})
.AddPolicyHandler(timeoutPolicy); // << NEW CODE
_serviceProvider = collection.BuildServiceProvider();
}
- 2 秒后,Polly 的 TimeoutPolicy 取消请求并抛出
TimeoutRejectedException
。- 它的
InnerException
是原来的TaskCanceledException
。
- 它的
最后让我们添加重试策略:
private static void RegisterServices()
{
var collection = new ServiceCollection();
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(2);
collection.AddHttpClient<INetworkService,NetworkService>(sonol =>
{
//sonol.Timeout = TimeSpan.FromSeconds(3);
sonol.BaseAddress = new Uri("http://www.google.com:81");
})
.AddPolicyHandler(Policy.WrapAsync(GetRetryPolicy(),timeoutPolicy)); // << NEW CODE
//.AddPolicyHandler(timeoutPolicy);
_serviceProvider = collection.BuildServiceProvider();
}
- 14 秒后(3+1 2 秒长请求和 3 2 秒长处罚)重试策略抛出原始异常,即innerPolicy 的
TimeoutRejectedException
。- 该异常的内部是 HttpClient 的
TaskCanceledException
。
- 该异常的内部是 HttpClient 的
更新:捕捉评论的精髓
我知道所有尝试都失败的点在哪里?
当您的 Polly 装饰 HttpClient
抛出 TimeoutRejectedException
时,您可以确定所有尝试都失败了。因此,您应该在类型化的客户端内使用 try-catch 包装 GetAsync
。
我应该检查异常以查看它是 timeoutException 吗?
如果 url 格式错误,它将抛出不同的异常。因此,如果您捕获 TimeoutRejectedException
,则意味着下游不可用或已过载。
我是否需要捕获第一个 TimeoutRejectedException 异常才能识别退休失败?
从消费者的角度来看,会有一个例外。重试策略会抛出它
- 重试次数用完时
- 或者当它没有配置为处理它时。
- 所有未通过
Handle<>
或Or<>
调用明确列出的异常都被视为未处理。这意味着如果没有任何重试,策略就会抛出该错误。
- 所有未通过
换句话说,如果客户端在给定的时间段内未收到来自下游系统的答复,则将抛出 TimeoutRejectedException
。但如果存在网络问题,它也可能会抛出 HttpRequestException
。
- 如果重试被配置为处理该问题,那么您可以确定如果它被抛出,那么所有重试尝试都失败了。
- 如果未配置,则无需任何重试就会抛出
HttpRequestException
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。