Reputation: 155
My original intention was to retry multiple times when the request itself times out, such as when trying to communicate to another micro service which is down for a couple of seconds in the hope it is a temporary failure. If there is a simpler solution to do just that it would suffice. I decided to manually set timeout per retry using a wrapping policy, hoping to achieve the same result.
I've seen a similar solution not using httpclientfactory here Use a specific timeout connected to a retrypolicy, but it doesn't work for me.
My code looks like this:
services.AddHttpClient("retryclient", client =>
{
client.Timeout = TimeSpan.FromSeconds(100);
}).AddPolicyHandler((servs, request) =>
Policy.HandleResult<HttpResponseMessage>(r =>
{
return r.StatusCode == HttpStatusCode.NotFound; //(1)
}).
.OrTransiesntHttpError().
WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
onRetry: (exception, timespan, retryAttempt, context) =>
{ // using servs to log // });
}).WrapAsync(Policy.TimeoutAsync(1)));
I have checked that the retry policy works when I try to access a 'not-found' adress without wrapping the timeout policy and it works fine. I've also tried to use line (1) with the status code HttpStatusCode.RequestTimeout
instead of not found for my case, but it doesn't work.
When I am using the wrapping and trying to access a service which is down it throws a Polly.Timeout.TimeoutRejectedException
on the first try as I would have expected, but doesn't retry again. I couldn't figure a way to retry multiple time, either with a set timeout for each retry, or just when the request itself time outs not using a timeout policy.
Edit: After further reading https://cm.engineering/transient-timeouts-and-the-retry-rabbit-hole-net-4-5-f406cebbf194 it seems my problem is inside the policy handling I don't have access to the cancellation token of the HttpClient. I assume I can fix it by overriding the sendAsync method as shown in link. Is there an elegant way to do same while creating the factory?
Upvotes: 4
Views: 6433
Reputation: 8156
The Polly documentation on HttpClientFactory covers this in a section labelled applying timeouts:
You may want the retry policy to retry if any individual try timed out. To do this, make the retry policy handle the
TimeoutRejectedException
which Polly's timeout policy throws.
So:
services.AddHttpClient("retryclient", client =>
{
client.Timeout = TimeSpan.FromSeconds(100);
}).AddPolicyHandler((servs, request) =>
Policy.HandleResult<HttpResponseMessage>(r =>
{
return r.StatusCode == HttpStatusCode.NotFound; //(1)
}).
.OrTransientHttpError()
.Or<TimeoutRejectedException>() // ** ADDED **
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
onRetry: (exception, timespan, retryAttempt, context) =>
{ // using servs to log // });
})
.WrapAsync(Policy.TimeoutAsync(1)));
Polly passes the CancellationToken
to the internal .SendAsync()
call correctly; no changes should be needed concerning that.
Upvotes: 10