在 .Net Core 中捕获 Polly 中的最后一个异常?
Catching the last exception in Polly in .Net Core?
我正在使用 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
Exception : (TimeoutException) The delegate executed asynchronously through TimeoutPolicy did not complete within the timeout.
我想在上次尝试失败后发送电子邮件。
问题:
如何捕获 final 异常?是否有任何内置机制让我知道 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
。
- 那个异常的 Inner 是 HttpClient 的
TaskCanceledException
。
更新:捕捉评论的精华
Where is the point where I know that all attempts have failed?
当你的 Polly decorated HttpClient
抛出 TimeoutRejectedException
时,你可以确定所有尝试都失败了。因此,您应该将 GetAsync
与 try-catch 包装在类型化的客户端中。
Should I check the exception to see that it's timeoutException?
如果格式不正确url,它将抛出不同的异常。因此,如果您发现 TimeoutRejectedException
,则意味着下游不可用或过载。
Do I need to catch first TimeoutRejectedException exception in order to recognize retires have failed?
从消费者的角度来看,只有一个例外。重试策略会抛出
- 当它用完重试次数时
- 或未配置为处理它时。
- 所有未通过
Handle<>
或 Or<>
调用明确列出的异常都被视为未处理。这意味着无需重试,策略就会抛出该错误。
换句话说,如果客户端在给定时间段内未收到来自下游系统的应答,将抛出 TimeoutRejectedException
。但如果存在网络问题,它也可能会抛出 HttpRequestException
。
- 如果重试配置为处理该问题,那么您可以确定,如果它被抛出,那么所有重试尝试都会失败。
- 如果未配置,则在不重试的情况下将抛出
HttpRequestException
。
我正在使用 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
Exception : (TimeoutException) The delegate executed asynchronously through TimeoutPolicy did not complete within the timeout.
我想在上次尝试失败后发送电子邮件。
问题:
如何捕获 final 异常?是否有任何内置机制让我知道 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
。- 那个异常的 Inner 是 HttpClient 的
TaskCanceledException
。
- 那个异常的 Inner 是 HttpClient 的
更新:捕捉评论的精华
Where is the point where I know that all attempts have failed?
当你的 Polly decorated HttpClient
抛出 TimeoutRejectedException
时,你可以确定所有尝试都失败了。因此,您应该将 GetAsync
与 try-catch 包装在类型化的客户端中。
Should I check the exception to see that it's timeoutException?
如果格式不正确url,它将抛出不同的异常。因此,如果您发现 TimeoutRejectedException
,则意味着下游不可用或过载。
Do I need to catch first TimeoutRejectedException exception in order to recognize retires have failed?
从消费者的角度来看,只有一个例外。重试策略会抛出
- 当它用完重试次数时
- 或未配置为处理它时。
- 所有未通过
Handle<>
或Or<>
调用明确列出的异常都被视为未处理。这意味着无需重试,策略就会抛出该错误。
- 所有未通过
换句话说,如果客户端在给定时间段内未收到来自下游系统的应答,将抛出 TimeoutRejectedException
。但如果存在网络问题,它也可能会抛出 HttpRequestException
。
- 如果重试配置为处理该问题,那么您可以确定,如果它被抛出,那么所有重试尝试都会失败。
- 如果未配置,则在不重试的情况下将抛出
HttpRequestException
。