Skip to content

Instantly share code, notes, and snippets.

@pwelter34
Created February 27, 2020 19:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pwelter34/5482b04498b33ea8647d69c35f4d7ee7 to your computer and use it in GitHub Desktop.
Save pwelter34/5482b04498b33ea8647d69c35f4d7ee7 to your computer and use it in GitHub Desktop.
Retry code
/// <summary>
/// Retry helpers for common retry scenario
/// </summary>
public static class Retry
{
/// <summary>
/// The default retry count
/// </summary>
public const int RetryCount = 5;
/// <summary>
/// The default retry delay in milliseconds
/// </summary>
public const int RetryDelay = 500;
/// <summary>
/// Retries the <paramref name="retryDelegate"/> when the specified <paramref name="retryCondition"/> evaluates to true.
/// </summary>
/// <typeparam name="TResult">The type of the return value.</typeparam>
/// <param name="retryDelegate">The <see langword="delegate"/> to retry.</param>
/// <param name="retryCondition">The <see langword="delegate"/> to evaluate if should retry.</param>
/// <param name="retryCount">The number of times to retry.</param>
/// <param name="retryDelay">The amount of time in milliseconds to sleep before retry.</param>
public static TResult WhenCondition<TResult>(Func<TResult> retryDelegate, Func<TResult, bool> retryCondition = null, int retryCount = RetryCount, int retryDelay = RetryDelay)
{
TResult result;
if (retryCondition == null)
{
retryCondition = value => value == null;
}
while (retryCount-- > 0)
{
result = retryDelegate();
if (!retryCondition(result))
{
return result;
}
Thread.Sleep(retryDelay);
}
return default(TResult);
}
/// <summary>
/// Retries the specified <see langword="delegate"/> when an <see cref="System.Exception"/> occurs.
/// </summary>
/// <param name="retryDelegate">The <see langword="delegate"/> to retry.</param>
/// <param name="retryCount">The number of times to retry.</param>
/// <param name="retryDelay">The amount of time in milliseconds to sleep before retry.</param>
public static void WhenException(Action retryDelegate, int retryCount = 5, int retryDelay = RetryDelay)
{
WhenException<Exception>(retryDelegate, retryCount, retryDelay);
}
/// <summary>
/// Retries the specified <see langword="delegate"/> when an exception of <typeparamref name="TException"/> occurs.
/// </summary>
/// <typeparam name="TException">The type of the exception.</typeparam>
/// <param name="retryDelegate">The <see langword="delegate"/> to retry.</param>
/// <param name="retryCount">The number of times to retry.</param>
/// <param name="retryDelay">The amount of time in milliseconds to sleep before retry.</param>
public static void WhenException<TException>(Action retryDelegate, int retryCount = RetryCount, int retryDelay = RetryDelay)
where TException : Exception
{
if (retryDelegate == null)
{
throw new ArgumentNullException(nameof(retryDelegate));
}
while (retryCount-- > 0)
{
try
{
retryDelegate();
return;
}
catch (TException)
{
if (retryCount <= 0)
throw;
Thread.Sleep(retryDelay);
}
}
}
/// <summary>
/// Retries the specified <see langword="delegate"/> when an <see cref="System.Exception"/> occurs.
/// </summary>
/// <typeparam name="TResult">The type of the return value.</typeparam>
/// <param name="retryDelegate">The <see langword="delegate"/> to retry.</param>
/// <param name="retryCount">The number of times to retry.</param>
/// <param name="retryDelay">The amount of time in milliseconds to sleep before retry.</param>
/// <returns>The result of the <paramref name="retryDelegate"/>.</returns>
public static TResult WhenException<TResult>(Func<TResult> retryDelegate, int retryCount = RetryCount, int retryDelay = RetryDelay)
{
return WhenException<Exception, TResult>(retryDelegate, retryCount, retryDelay);
}
/// <summary>
/// Retries the specified <see langword="delegate"/> when an exception of <typeparamref name="TException"/> occurs.
/// </summary>
/// <typeparam name="TException">The type of the exception.</typeparam>
/// <typeparam name="TResult">The type of the return value.</typeparam>
/// <param name="retryDelegate">The <see langword="delegate"/> to retry.</param>
/// <param name="retryCount">The number of times to retry.</param>
/// <param name="retryDelay">The amount of time in milliseconds to sleep before retry.</param>
/// <returns>The result of the <paramref name="retryDelegate"/>.</returns>
public static TResult WhenException<TException, TResult>(Func<TResult> retryDelegate, int retryCount = RetryCount, int retryDelay = RetryDelay)
where TException : Exception
{
if (retryDelegate == null)
{
throw new ArgumentNullException(nameof(retryDelegate));
}
while (retryCount-- > 0)
{
try
{
return retryDelegate();
}
catch (TException)
{
if (retryCount <= 0)
throw;
Thread.Sleep(retryDelay);
}
}
return default(TResult);
}
}
[TestClass]
public class RetryTests
{
[TestMethod]
public void RetryWhenConditionPass()
{
Func<int> retryDelegate;
Func<int, bool> retryCondition;
int count = 1;
int result;
retryDelegate = new Func<int>(() => count++);
retryCondition = new Func<int, bool>(v => v < 5);
result = Retry.WhenCondition<int>(retryDelegate, retryCondition, retryDelay: 10);
result.Should().Be(5);
count.Should().Be(6);
}
[TestMethod]
public void RetryWhenConditionFail()
{
Func<int> retryDelegate;
Func<int, bool> retryCondition;
int count = 1;
int result;
retryDelegate = new Func<int>(() => count++);
retryCondition = new Func<int, bool>(v => v < 10);
result = Retry.WhenCondition<int>(retryDelegate, retryCondition, retryDelay: 10);
result.Should().Be(0);
count.Should().Be(6);
}
[TestMethod]
public void RetryWhenExceptionPass()
{
Action retryDelegate;
int count = 1;
bool pass = false;
retryDelegate = new Action(() =>
{
count++;
if (count < 5)
throw new InvalidOperationException("Test exception");
pass = true;
});
Retry.WhenException<InvalidOperationException>(retryDelegate, retryDelay: 10);
count.Should().Be(5);
pass.Should().BeTrue();
}
[TestMethod]
public void RetryWhenExceptionThrow()
{
Action assertionDelegate;
Action retryDelegate;
int count = 0;
retryDelegate = new Action(() =>
{
count++;
throw new InvalidOperationException("Test exception");
});
assertionDelegate = ()=> Retry.WhenException(retryDelegate, retryDelay: 10);
assertionDelegate.Should().Throw<InvalidOperationException>();
count.Should().Be(5);
}
[TestMethod]
public void RetryWhenExceptionThrowType()
{
Action assertionDelegate;
Action retryDelegate;
int count = 0;
retryDelegate = new Action(() =>
{
count++;
if (count < 2)
throw new InvalidOperationException("Test");
throw new InvalidProgramException("Test");
});
assertionDelegate = () => Retry.WhenException<InvalidOperationException>(retryDelegate, retryDelay: 10);
assertionDelegate.Should().Throw<InvalidProgramException>();
count.Should().Be(2);
}
[TestMethod]
public void RetryWhenExceptionResultPass()
{
Func<int> retryDelegate;
int count = 1;
int result;
retryDelegate = new Func<int>(() =>
{
count++;
if (count < 5)
throw new InvalidOperationException("Test exception");
return count;
});
result = Retry.WhenException(retryDelegate, retryDelay: 10);
result.Should().Be(5);
count.Should().Be(5);
}
[TestMethod]
public void RetryWhenExceptionResultFail()
{
Action assertionDelegate;
Func<int> retryDelegate;
int count = 0;
int result;
retryDelegate = new Func<int>(() =>
{
count++;
throw new InvalidOperationException("Test exception");
});
assertionDelegate = () => result = Retry.WhenException(retryDelegate, retryDelay: 10);
assertionDelegate.Should().Throw<InvalidOperationException>();
count.Should().Be(5);
}
[TestMethod]
public void RetryWhenExceptionResultType()
{
Action assertionDelegate;
Func<int> retryDelegate;
int count = 0;
int result;
retryDelegate = new Func<int>(() =>
{
count++;
if (count < 2)
throw new InvalidOperationException("Test");
throw new InvalidProgramException("Test");
});
assertionDelegate = () => result = Retry.WhenException<InvalidOperationException, int>(retryDelegate, retryDelay: 10);
assertionDelegate.Should().Throw<InvalidProgramException>();
count.Should().Be(2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment