Alejandro
Alejandro

Reputation: 381

After a 500 response no requests are sent again until process is restarted

I am using Polly to implement request retries. However, after a 500 response is returned for a request, not only does Polly not send a request when it retries but no requests are sent at all until the process is restarted. Instead Polly just waits until there is a timeout. The following is the code:

var timeoutPolicy = TimeoutPolicy
    .TimeoutAsync<HttpResponseMessage>(c => c.GetTimeout() ?? TimeSpan.FromSeconds(30)); //timeout para cada intento

var retryPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .Or<TimeoutRejectedException>() //tirado por la TimeoutPolicy
    .WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) });

var policyHandler = new PolicyHandler(Policy.WrapAsync(retryPolicy, timeoutPolicy));

How can I fix the code such that Polly actually sends the request when it retries after a 500 and also for following requests?

Upvotes: 1

Views: 1127

Answers (2)

Alejandro
Alejandro

Reputation: 381

The error was caused by the following issue

This is how I fixed it:

var retryPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .Or<TimeoutRejectedException>() //tirado por la TimeoutPolicy
    .WaitAndRetryAsync(new[] 
      { 
        TimeSpan.FromSeconds(1), 
        TimeSpan.FromSeconds(5), 
        TimeSpan.FromSeconds(10) 
      }, 
      onRetry: (x, _) =>
      {
          //dispose response when retrying
          x.Result?.Dispose();
      });

Upvotes: 1

Peter Csala
Peter Csala

Reputation: 22819

I do believe that the application crash is not related to these policies.

I've amended your code with some debugging logs like this:

public static readonly HttpClient client = new HttpClient();
public static async Task Main(string[] args)
{
    var sw = Stopwatch.StartNew();
    Console.WriteLine($"{sw.Elapsed.Seconds}: Application starts");

    var timeoutPolicy = TimeoutPolicy
        .TimeoutAsync<HttpResponseMessage>(
            TimeSpan.FromSeconds(30),
            onTimeoutAsync: (ctx, ts, t) => {
                Console.WriteLine($"{sw.Elapsed.Seconds}: Timeout has occurred");
                return Task.CompletedTask;
        });

    var retryPolicy = HttpPolicyExtensions
        .HandleTransientHttpError()
        .Or<TimeoutRejectedException>() 
        .WaitAndRetryAsync(
            new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) },
            onRetryAsync: (dr, ts) => {
                Console.WriteLine($"{sw.Elapsed.Seconds}: Retry will be triggered");
                return Task.CompletedTask;
            });

    var strategy = Policy.WrapAsync(retryPolicy, timeoutPolicy);
    await strategy.ExecuteAsync(async (ct) => {
        var response = await client.GetAsync("https://httpstat.us/500");
        Console.WriteLine($"{sw.Elapsed.Seconds}: Response has been received");
        return response;
    }, CancellationToken.None);

    Console.WriteLine($"{sw.Elapsed.Seconds}: Application finishes");
}
  • It prints Response has been received whenever the httpClient has received a response
    • I've used httpstat.us only for testing purposes
  • It prints Timeout has occurred whenever the httpClient did not receive a response under 30 seconds
  • It prints Retry will be triggered whenever the retry policy should be fired but before the delay penalty
  • It prints Application finishes whenever all the retries are issued and none of them succeeded or when one of the requests succeeds

With the current setup the output would look like this:

1: Response has been received
1: Retry will be triggered
2: Response has been received
2: Retry will be triggered
8: Response has been received
8: Retry will be triggered
18: Response has been received
18: Application finishes

So as you can see, we have issued 4 requests (one initial and 3 retries) without luck. But at the end the application has continued its work.

Upvotes: 1

Related Questions