I'm using Polly with .net Core. My ConfigureServices
is :
private static void ConfigureServices()
{
var collection = new ServiceCollection();
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(3);
collection.AddHttpClient<INetworkService, NetworkService>(s=>
{
s.BaseAddress = new Uri("http://google.com:81"); //this is a deliberate timeout url
})
.AddPolicyHandler((a,b)=>GetRetryPolicy(b))
.AddPolicyHandler(timeoutPolicy); ;
...
}
This is the GetRetryPolicy
function:
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(HttpRequestMessage req)
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => httpStatusCodesWorthRetrying.Contains(msg.StatusCode)) // see below
.Or<TimeoutRejectedException>()
.Or<TaskCanceledException>()
.Or<OperationCanceledException>()
.WaitAndRetryAsync(3, retryAttempt =>
{
return TimeSpan.FromSeconds(3);
}, onRetry: (response, delay, retryCount, context) =>
{
Console.WriteLine($"______PollyAttempt_____ retryCount:{retryCount}__FOR_BaseUrl_{req.RequestUri.ToString()}");
});
}
Those are the httpcodes I want to retry :
static HttpStatusCode[] httpStatusCodesWorthRetrying = {
HttpStatusCode.RequestTimeout, // 408
HttpStatusCode.InternalServerError, // 500
HttpStatusCode.BadGateway, // 502
HttpStatusCode.ServiceUnavailable, // 503
HttpStatusCode.GatewayTimeout // 504
};
Ok. And this is the actual invocation :
public async Task Work()
{
try
{
HttpResponseMessage response = await _httpClient.GetAsync("");
Console.WriteLine("After work");
}
catch (TimeoutRejectedException ex)
{
Console.WriteLine("inside TimeoutRejectedException");
}
catch (Exception ex)
{
Console.WriteLine("inside catch main http");
}
}
The output is :
_PollyAttempt retryCount:1__FOR_BaseUrl_http://google.com:81/
_PollyAttempt retryCount:2__FOR_BaseUrl_http://google.com:81/
_PollyAttempt retryCount:3__FOR_BaseUrl_http://google.com:81/
inside TimeoutRejectedException
(notice it throws) Which is OK. Because Polly throws after this invalid URL is timeout.
But if I change the http://google.com:81/
to an "internal server error" url : (this return 500)
https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
Then it doesn't throw but continues :
_PollyAttempt retryCount:1__FOR_BaseUrl_https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
_PollyAttempt retryCount:2__FOR_BaseUrl_https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
_PollyAttempt retryCount:3__FOR_BaseUrl_https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
After work
(notice "after work" at the end)
Question:
Why does Polly throw at timeout, But doesn't throw at another condition ?
I explictly wrote : .OrResult(msg => httpStatusCodesWorthRetrying.Contains(msg.StatusCode))
and 500 is one of them.
As @StephenCleary said that's how the Polly works.
First let me share with you the cleaned up version of your code
then I will give you some explanation about the observed behaviours.
ConfigureServices
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(3,
onTimeoutAsync: (_, __, ___) => {
Console.WriteLine("Timeout has occured");
return Task.CompletedTask;
});
services.AddHttpClient<INetworkService, NetworkService>(
client => client.BaseAddress = new Uri("https://httpstat.us/500"))
.AddPolicyHandler((_, request) => Policy.WrapAsync(GetRetryPolicy(request), timeoutPolicy));
GetRetryPolicy
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(HttpRequestMessage req)
=> HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>()
.Or<OperationCanceledException>()
.WaitAndRetryAsync(3,
_ => TimeSpan.FromSeconds(3),
onRetry: (_, __, retryCount, ___) =>
Console.WriteLine($"POLLY retryCount:{retryCount} baseUrl: {req.RequestUri}"));
http://google.com:81
TimeoutRejectedException
is thrownTimeoutRejectedException
https://httpstat.us/500
Because there is a lack of EnsureSuccessStatusCode
method call that's why no exception is being thrown.
As you can see in the second example the TimeoutPolicy is not triggered at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With