0

I have implemented the below Polly Policies for the HttpClient.

IHostBuilder hostBuilder = new HostBuilder().ConfigureServices((hostContext, services) =>
                                   {
                                       AppSettings appSettings = new AppSettings();
                                       IConfigurationRoot configuration = GetConfiguration();
                                       configuration.Bind("Configuration", appSettings);

                                    services.AddSingleton(appSettings);                                          services.AddHttpClient("WebAPI", client =>
                                       {
                                           client.BaseAddress = new Uri(appSettings.WebApiBaseAddress);
                                           client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                                       })
                                       .AddPolicyHandler(HttpClientPolicyHandler.WaitAndRetry(appSettings.RetryCount))
                                       .AddPolicyHandler(HttpClientPolicyHandler.Timeout(appSettings.TimeOut));

                                       services.AddHostedService<RDPersister>();
                                   });

        await hostBuilder.RunConsoleAsync();

public static class HttpClientPolicyHandler
{
    /// <summary>
    /// Create a Wait and Retry policy for HttpClient on the basis of specified Status Code and Timeout.
    /// </summary>
    /// <param name="retryCount">Number of retries.</param>
    /// <returns>Wait and Retry policy handler.</returns>
    public static IAsyncPolicy<HttpResponseMessage> WaitAndRetry(int retryCount)
    {
        return HttpPolicyExtensions.HandleTransientHttpError()
               .OrResult(msg => msg.StatusCode == HttpStatusCode.NotFound)
               .Or<TimeoutRejectedException>()
               .Or<HttpRequestException>()
               .WaitAndRetryAsync(retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
    }

    /// <summary>
    /// Create a Timeout policy for HttpClient.
    /// </summary>
    /// <param name="seconds">Timeout.</param>
    /// <returns>Timeout policy handler.</returns>
    public static IAsyncPolicy<HttpResponseMessage> Timeout(int seconds)
    {
        return Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(seconds));
    }
}

Below is the asynchronous call of the web api

private async void CallWebApi(string webApiJsonMessage)
{
    try
    {
        HttpClient client = _httpClientFactory.CreateClient("WebAPI");
            string uri = "api/CalculateOrder";

        HttpResponseMessage response = await client.PostAsync(uri, new StringContent(webApiJsonMessage, Encoding.UTF8, "application/json"));
        string token = await response.Content.ReadAsStringAsync();

            if (response.IsSuccessStatusCode)
            {          
            }
            else
            {
            }
     }
     catch (Exception ex)
     {
         _logger.Error($"Exception occurred while calling WebAPI: {ex.Message} for message : {webApiJsonMessage}");
     }
 }

But I want to create a synchronous call to WebAPI since I want to wait for the response to come. My question then in that case do I need to create sync policy in Polly and how??

And one more question the timeout policy will work for the entire retries. Do I need to create one more policy for single retry timeout as well?

Any help??

JacobHigs
  • 29
  • 6
  • @John: This is more in respect to Polly and its sync policy with combination to sync calling of web api. But the question u have mentioned its just how to make Sync calling. – JacobHigs Jun 20 '19 at 14:31
  • I've reopened your question, but I wonder why you want to make async code (the http request) sync. Can you explain your motivation? I ask because if you make `CallWebApi` an `async Task`, you can `await` it to get the response. – ProgrammingLlama Jun 20 '19 at 14:33
  • @John: We usually received too many messages to the application which is calling this WebApi. We actually then end up sending too many calls to the web API which became the problem. – JacobHigs Jun 20 '19 at 15:31
  • Regarding timeout-for-whole-operation versus timeout-per-try with HttpClientFactory, this is [documented in the Polly + HttpClientFactory documentation](https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory#use-case-applying-timeouts) – mountain traveller Jun 20 '19 at 18:04
  • As others say, using `await` with async (as already in the code posted in the q) does wait for the response to come. Changing to sync (other factors being equal) will not improve this; it will consume more resources in your caller (it will block calling threads). You could consider other ways of limiting throughput, such as serial rate-limiting, or parallelism throttling such as with Polly [Bulkhead policy](https://github.com/App-vNext/Polly/wiki/Bulkhead). – mountain traveller Jun 20 '19 at 19:05
  • 1
    So just to be 100% certain: you have tried changing `async void CallWebApi` to `async Task CallWebApi` and used an async Polly policy, which you have awaited, and it hasn't worked for you? That's certainly what I'd do, anyway. As indicated by the question I previously marked yours as a duplicate of, you can't wait for `async void` because it doesn't return a `Task`. I think this is a good reason why you might be having this problem. – ProgrammingLlama Jun 20 '19 at 23:39
  • +1 to what John said (I missed the `async void`). For clarity: you can't `await` an `async void`; a call to an `async void` will return before the result is available. If you simply change to `async Task CallWebApi(...)` then a call `await CallWebApi(...)` (whether through a Polly policy or not) will wait for the response to come. – mountain traveller Jun 21 '19 at 12:18

0 Answers0