1

I'm trying to implement a Retry/Timeout procedure to access a webservice, with Polly and Refit. I have a timeout policy of 10 seconds (Polly.Timeout.TimeoutRejectedException on timeout). I have a retry policy of 2 attempts. I have a userCancellationToken than can be canceled by the user. If I don't set a Polly timeout policy, the client default timeouts after 100s with a System.IO.IOException

While this code basically works, I have some questions:

1) Is my code mostly correct?

2) If my timeout is at 10s, and I force my server to answer in 15s, as a timeout test, this code correctly does 3 attempts of 10s each and then fails, but after a few seconds I get displayed 3 "Success after...", meaning that the task was still running and waiting for data, even if Polly canceled it. How can I cancel the running task(s)?

3) If my server is unreachable I get a System.Net.Sockets.SocketException after 4 seconds. How can I reduce this timeout?

        var timeOutPolicy = Policy
            .TimeoutAsync(
                10,
                TimeoutStrategy.Pessimistic);

        var retryPolicy = Policy
          .Handle<Exception>()              
          .RetryAsync(2, (exception, attempt) =>
          {                  
              sw.Stop();
              progress.Report($"Error after {sw.Elapsed}");
              progress.Report($"New attempt {attempt}");

              if (exception.InnerException is System.Net.Sockets.SocketException)
              {
                  progress.Report("Catched: SocketException (No server running or not reachable)");                      
              }
              if (exception.InnerException is System.IO.IOException)
              {
                  progress.Report("Catched: IOException (normal timeout)");                      
              }
              if (exception is Polly.Timeout.TimeoutRejectedException)
              {
                  progress.Report("Catched: Polly Exception (timeout set by Polly)");
              }                  
              if (exception.InnerException is ApiException) progress.Report("Catched: ApiException");
          });

        var policyWrap = Policy.WrapAsync(retryPolicy, timeOutPolicy);

        try
        {
            await policyWrap.ExecuteAsync(async (ct) =>
            {
                sw.Restart();                    

                progress.Report("Execute");                    

                var api = RestService.For<ICTServerApi>("http://localhost:3105/json/reply/ReqUtenti");

                respUtenti = await api.GetUtentiAsync(reqUtenti, userCancellationToken).ConfigureAwait(false);

                sw.Stop();
                progress.Report($"Success after {sw.Elapsed}");
            }, userCancellationToken).ConfigureAwait(false);
        }            

Thanks!

Reza Jenabi
  • 3,884
  • 1
  • 29
  • 34
Mattia Durli
  • 757
  • 7
  • 19
  • 1
    about point 2: you never use `ct` .. maybe you should combine it with userCT and pass to `GetUtentiAsync` – Selvin Dec 09 '19 at 14:31
  • I tried await api.GetUtentiAsync(reqUtenti, ct) too, but behavior doesn't change – Mattia Durli Dec 09 '19 at 14:47
  • 2
    `TimeoutStrategy.Pessimistic` is designed for delegates which don't honour `CancellationToken`s. If the refit-generated api honours cancellation, switch to `TimeoutStrategy.Optimistic` instead. https://github.com/App-vNext/Polly/wiki/Timeout#optimistic-timeout – mountain traveller Dec 09 '19 at 18:55
  • Thanks, I switched to Optimistic and used the ct in the Refit call, it cancel the Task too. – Mattia Durli Dec 13 '19 at 16:18

0 Answers0