Skip to content

Instantly share code, notes, and snippets.

@Kennethtruyers
Created November 26, 2017 20:41
Show Gist options
  • Save Kennethtruyers/d61ac5cec64dc57e03dae67f0ce6b924 to your computer and use it in GitHub Desktop.
Save Kennethtruyers/d61ac5cec64dc57e03dae67f0ce6b924 to your computer and use it in GitHub Desktop.
public interface IRetry
{
Task RetryAsync(Func<Task> operation, CancellationToken cancellationToken);
Task<T> RetryAsync<T>(Func<Task<T>> operation, CancellationToken cancellationToken);
}
public interface IRetrySource
{
IRetry Immediate(Predicate<Exception> shouldRetry, int maximumRetries);
IRetry WithLinearBackoff(Predicate<Exception> shouldRetry, int maximumRetries, TimeSpan firstDelay, TimeSpan delayIncrement);
IRetry WithExponentialBackoff(Predicate<Exception> shouldRetry, int maximumRetries, TimeSpan firstDelay);
}
public class EndjinRetrySource : IRetrySource
{
public IRetry Immediate(Predicate<Exception> shouldRetry, int maximumRetries) =>
new Retry(shouldRetry, new Count(maximumRetries));
public IRetry WithLinearBackoff(Predicate<Exception> shouldRetry, int maximumRetries, TimeSpan firstDelay, TimeSpan delayIncrement)
{
var strategy = delayIncrement == TimeSpan.Zero
? (IRetryStrategy) new Linear(firstDelay, maximumRetries)
: new Incremental(maximumRetries, firstDelay, delayIncrement);
return new Retry(shouldRetry, strategy);
}
public IRetry WithExponentialBackoff(Predicate<Exception> shouldRetry, int maximumRetries, TimeSpan firstDelay) =>
new Retry(shouldRetry, new Backoff(maximumRetries, firstDelay));
}
class Retry : IRetry, IRetryPolicy
{
readonly Predicate<Exception> _shouldRetry;
readonly IRetryStrategy _strategy;
public Retry(Predicate<Exception> shouldRetry, IRetryStrategy strategy)
{
_shouldRetry = shouldRetry;
_strategy = strategy;
}
public Task RetryAsync(Func<Task> operation, CancellationToken cancellationToken) =>
Retriable.RetryAsync(operation, cancellationToken, _strategy, this);
public Task<T> RetryAsync<T>(Func<Task<T>> operation, CancellationToken cancellationToken) =>
Retriable.RetryAsync(operation, cancellationToken, _strategy, this);
public bool CanRetry(Exception exception) =>
_shouldRetry == null || _shouldRetry(exception);
}
public static class RetryExtensions
{
public static void Retry(this IRetry retry, Action operation) =>
retry.RetryAsync(() =>
{
operation();
return Task.FromResult(default(object));
},
CancellationToken.None)
.Wait();
public static Task<TResult> Retry<TResult>(this IRetry retry, Func<TResult> operation) =>
retry.RetryAsync(() => Task.FromResult(operation()), CancellationToken.None);
public static Task RetryAsync(this IRetry retry, Func<Task> operation) =>
retry.RetryAsync(operation, CancellationToken.None);
public static Task<TResult> RetryAsync<TResult>(this IRetry retry, Func<Task<TResult>> operation) =>
retry.RetryAsync(operation, CancellationToken.None);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment