question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to use WaitAndRetry with jitter retry intervals depending on the Exception thrown

See original GitHub issue

I would like to apply a WaitAndRetry policy with different parameters, depending on the Exception thrown, for the jitter function calculating the retry intervals. Let’s say that for Type1Exception I would like to feed to the function a specific couple of maxValue and seedValue and for Type2Exception others. A simple jitter function that calculates the retry intervals is as follows:

IEnumerable<TimeSpan> GetRetryIntervals(int maxRetries, TimeSpan seedDelay, TimeSpan maxDelay)
{
     var jitterer = new Random();
     int retries = 0;
     double seed = seedDelay.TotalMilliseconds;
     double max = maxDelay.TotalMilliseconds;
     double current = seed;

      while (++retries <= maxRetries)
      {
         if (retries == maxRetries)
	 {
            yield return maxDelay;
	    yield break;
         }

	  current = Math.Min(max, Math.Max(seed, current * jitterer.NextDouble()));
	  yield return TimeSpan.FromMilliseconds(current);
  }
}

The only way I found to use the jitter with such requirements is to retrieve both jitter intervals before creating the policy and use retryCount as index:

var type1Intervals = GetRetryIntervals(10, TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(10000));
var type2Intervals = GetRetryIntervals(10, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(20000));

Policy
  .Handle<Exception>()
  .WaitAndRetryAsync(5, async (exception, retryCount) =>
   {
      if(exception is Type1Exception)
      {
          await Task.Delay(type1Intervals.ElementAt(retryCount)).ConfigureAwait(false);
      }
      if(exception is Type2Exception)
      {
          await Task.Delay(type2Intervals.ElementAt(retryCount)).ConfigureAwait(false);
      }
   }   
  })
  // execute the command
  .ExecuteAsync(async () => await DoSomething())
  .ConfigureAwait(false);

This solution indeed works but it is neither elegant not optimized. Is there a more proper way to implement it?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
reisenbergercommented, Dec 20, 2019

@FrancescoReviso The code in the comment above will apply the “type 1” WaitAndRetry behaviour to any exception is Type1Exception, and the other WaitAndRetry behaviour to all other exceptions.

Re:

Is it also possible to apply an “except logic” to the exception thrown? Suppose I would like to apply a WaitAndRetry behaviour for all the types of exceptions except one, in this case Type1Exception

If you want the WaitAndRetry policy to not apply at all for one exception type, you can make a policy to handle all exceptions except that, by using a single handle clause like this:

.Handle<Exception>(e => !(e is Type1Exception))
1reaction
reisenbergercommented, Dec 20, 2019

A couple of technical comments about the original quoted code, in case you eventually settle on a solution more like that.

First, with .WaitAndRetryAsync(...), you don’t need to manually call await Task.Delay(type1Intervals.ElementAt(retryCount)) yourself. The call to await Task.Delay(...) is already built in to the policy implementation. You only need to configure the policy to specify the delay timespans, as shown in the readme examples for WaitAndRetry.

Second, be aware that:

var type1Intervals = GetRetryIntervals(10, TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(10000));

with

type1Intervals.ElementAt(retryCount)

will get a new enumerator at each call to .ElementAt(...), and thus each call to .ElementAt(retryCount) in your original code will in fact be based on a different, freshly-realised sequence of the enumerable. With the original code, you might want to add a .ToList() or .ToArray() thus:

var type1Intervals = GetRetryIntervals(...).ToArray();

to reify the sequence just once.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Polly.Contrib.WaitAndRetry
Polly.Contrib.WaitAndRetry is an extension library for Polly containing helper methods for a variety of wait-and-retry strategies.
Read more >
How to throw final error using WaitAndRetry and Execute?
1 Answer 1 · If the retry limit has not been exceeded then it will perform yet another retry attempt · If the...
Read more >
Better Retries with Exponential Backoff and Jitter
We can use the exponential backoff algorithm in Resilience4j retry by configuring its IntervalFunction that accepts an initialInterval and a ...
Read more >
Polly 7.2.4
Pow(2, retryAttempt)) ); // Retry a specified number of times, using a function to // calculate the duration to wait between retries based...
Read more >
Exploring the Polly.Contrib.WaitAndRetry helpers - Ben Hyrman
In my code, I use Polly in several places to retry remote calls. ... After the last wait and retry, Polly will kick...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found