Search code examples
c#httpclientpolly

14s delay with HttpClient and Polly


I am using httpClient to do a POST request. I am using Polly for retries. What is happening is that the first attempt takes 14s even though I specified a retry time of 2s. The first attempt fails after 14s, then there is a 2s gap until the second attempt. What I want it to try every 2s and timeout and retry on any error. Is this the right way of doing it?

            var retryPolicy = Policy
                .Handle<Exception>()    // retry on any
                .WaitAndRetryAsync(6, 
                    retryAttempt => TimeSpan.FromMilliseconds(2000), 
                    (response, calculatedWaitDuration, ctx) =>
                    {
                        Log.LogError($"Failed attempt {attempt++}. Waited for {calculatedWaitDuration}. Exception: {response?.ToString()}");
                    });
            HttpResponseMessage httpResp = null;
            await retryPolicy.ExecuteAsync(async () =>
            {
                httpResp = await DoPost();
                httpResp?.EnsureSuccessStatusCode(); // throws HttpRequestException
                return httpResp;
            });


            var respBody = await httpResp.Content.ReadAsStringAsync();
            return respBody;

            async Task<HttpResponseMessage> DoPost()
            {
                var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url)
                {
                    Content = new StringContent(json, Encoding.UTF8, Constants.JsonContentType),
                    Headers = { Authorization = await GetAuthenticationTokenAsync() }
                };
                ServicePointManager.Expect100Continue = false;
                var httpResponseMessage = await StaticHttpClient.SendAsync(httpRequestMessage).ConfigureAwait(false);
                return httpResponseMessage;
            }

Solution

  • The first attempt takes 14s even though I specified a retry time of 2s. The first attempt fails after 14s, then there is a 2s gap until the second attempt.

    That is correct. WaitAndRetry is about how long to wait after a failure, before retrying, as specified in the documentation.

    What I want it to try every 2s and timeout and retry on any error.

    To enforce a timeout use Polly's Timeout policy. To both impose a timeout and retry, combine both Timeout and Retry policies using PolicyWrap. So, you might adapt your code like this:

            var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(2000));
    
            var retryPolicy = Policy
                .Handle<Exception>()    // retry on any
                .WaitAndRetryAsync(6,  // or just RetryAsync() if you don't want any wait before retrying
                    retryAttempt => /* a timespan, _if you want a wait before retrying */, 
                    (response, calculatedWaitDuration, ctx) =>
                    {
                        Log.LogError($"Failed attempt {attempt++}. Waited for {calculatedWaitDuration}. Exception: {response?.ToString()}");
                    });
    
            var combinedPolicy = retryPolicy.WrapAsync(timeoutPolicy);
    
            HttpResponseMessage httpResp = null;
            await combinedPolicy.ExecuteAsync(async () =>
            {
                httpResp = await DoPost();
                httpResp?.EnsureSuccessStatusCode(); // throws HttpRequestException
                return httpResp;
            });
    

    For more discussion and examples, see this similar stackoverflow question.