My previous
blog post
gave a very short description of
Polly and that we were
going to use it at work. The Polly library expose a set of options how to make
your software more resilient. The most common (my guess) is a simple retry
functionality, retry calling e.g. the database x number of times (x can also be
indefinitely). Other options are timeouts, cache functionality, fallbacks and a
couple more.
Our demand, however, didn’t exactly fit into the
retry policy of
Polly. We wanted to try x number of times (e.g. five times with two
seconds of sleep between tries), then sleep for some time (e.g. 30 or 60
seconds) and then try again five times. Repeat until success. Also, we
only wanted to log first time there is an error, and then when the try was
successful (after retries, not if successful on first attempt).
using System;
using Microsoft.Extensions.Logging;
using Polly;
using Polly.Retry;
namespace RetrySample
{
class RetryHelper
{
private readonly string HAS_DONE_RETRY = "HasDoneRetry";
private readonly string NBR_OF_RETRIES = "NbrOfRetries";
public int Execute(Func<int> action)
{
int response = 0;
RetryPolicy<int> policy = GetRetryPolicy();
var result = policy.ExecuteAndCapture(() =>
{
response = action.Invoke();
return response;
});
if (result.Context.ContainsKey(HAS_DONE_RETRY) && bool.Parse(result.Context[HAS_DONE_RETRY].ToString()))
{
Console.WriteLine($"Connection has been restored (after {result.Context[NBR_OF_RETRIES]} tries).");
}
return response;
}
private RetryPolicy<int> GetRetryPolicy()
{
int tmpWaitBeforeRetry = 2;
int tmpNbrOfRetries = 5;
int tmpWaitTime = 30;
RetryPolicy<int> policy = Policy
.HandleResult<int>(r => r == 0)
.WaitAndRetryForever(
sleepDurationProvider: (retryCount, result, context) =>
{
if (retryCount % tmpNbrOfRetries == 0)
{
// wait a little longer
return TimeSpan.FromSeconds(tmpWaitTime);
}
return TimeSpan.FromSeconds(tmpWaitBeforeRetry);
},
onRetry: (result, retry, calculatedWaitDuration, context) =>
{
if (retry == 1)
{
// only log first time
Console.WriteLine("Error sending message, retry until successful.");
context[HAS_DONE_RETRY] = true;
}
context[NBR_OF_RETRIES] = retry;
});
return policy;
}
}
}
Call the method with the following:
int result = _retryHelper.Execute(() => SomeMethod());
Comments
Post a Comment