Reputation: 33
Below I am showcasing the policy I am using to handle a PostAsync() request using a HttpClient. However, it seems like even though I passed generic Exception
, it still decides to throw it and fail to retry. I would like to ask why this is, and any workarounds.
_httpClientHandler = new HttpClientHandler()
{
UseCookies = true,
CookieContainer = new CookieContainer(),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
_httpClient = new HttpClient(_httpClientHandler) { Timeout = TimeSpan.FromSeconds(10) };
private async Task PreparePayloadByDate(DateTime date)
{
// Define the retry policy with exponential backoff
var retryPolicy = Policy<HttpResponseMessage>.Handle<HttpRequestException>()
.Or<TaskCanceledException>()
.OrResult(r => !r.IsSuccessStatusCode)
.WaitAndRetryForeverAsync(
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (exception, retryCount, timeSpan) =>
{
_logger.Log(LogEnums.Error, $"Attempt {retryCount} failed. Retrying in {timeSpan} seconds...");
});
var stringPayload = JsonConvert.SerializeObject(new { key = "days", options = date.ToString("yyyy-MM-dd") });
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var r1 = await retryPolicy.ExecuteAsync(() =>
_httpClient.PostAsync($"{_moduleConfig.Endpoint}/options/selected", httpContent));
}
I have also tried using a Policy Timeout rather than the HttpClient's Timeout. This seemed to have the same outcome. See Answer for more context
I would also like to add that this RetryPolicy is inside a try catch, and the exception being thrown is The request was canceled due to the configured HttpClient.Timeout of 15 seconds elapsing.
with a StackTrace of at System.Net.Http.HttpClient.HandleFailure(~)
.
Even when the timeout of the HttpClient is set to 3 minutes, 10 minutes, etc. It always will timeout. I believe its due to the url I am posting through rate limiting but not really sure. I can not get it to replicate in a browser.
Upvotes: 0
Views: 64
Reputation: 143098
TBH was not able to repro the issue, for me your code catches the timeout, but in general your code is not shielded from the exceptions since r2.EnsureSuccessStatusCode();
will throw for non-successes. In general you might want to handle results too in your policy. For example (for testing purposes):
var retryPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.OrResult(r => !r.IsSuccessStatusCode)
.WaitAndRetryForeverAsync(
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (exceptionOrResult, timeSpan) => ...);
Also you can use Microsoft.Extensions.Http.Polly
which has some default setup and convenient methods:
var policy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
retryAttempt)));
See the Implement HTTP call retries with exponential backoff with IHttpClientFactory and Polly policies doc.
Upvotes: 1