Skip to content

Instantly share code, notes, and snippets.

@dealproc
Last active January 12, 2016 19:07
Show Gist options
  • Save dealproc/5baeedc06142af832f0a to your computer and use it in GitHub Desktop.
Save dealproc/5baeedc06142af832f0a to your computer and use it in GitHub Desktop.
Retry logic for tasks
namespace YourProduct
{
/// <summary>
/// Task retry logic
/// </summary>
public static class TaskHelper
{
/// <summary>
/// Returns a task which retries the task returned by the specified task provider.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="taskProvider">The task returning function.</param>
/// <param name="maxAttemps">The maximum number of retries.</param>
/// <param name="shouldRetry">A predicate function which determines whether an exception should cause a retry. The default returns true for all exceptions.</param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
[DebuggerStepThrough]
public static Task<TResult> Retry<TResult>(Func<Task<TResult>> taskProvider, int maxAttemps, Func<Exception, bool> shouldRetry = null)
{
if (shouldRetry == null)
shouldRetry = ex => true;
return taskProvider()
.ContinueWith(task =>
RetryContinuation(task, taskProvider, maxAttemps, shouldRetry));
}
/// <summary>
/// A task continuation which attempts a retry if a task is faulted.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="task"></param>
/// <param name="taskProvider"></param>
/// <param name="attemptsRemaining"></param>
/// <param name="shouldRetry"></param>
/// <returns></returns>
static TResult RetryContinuation<TResult>(Task<TResult> task, Func<Task<TResult>> taskProvider, int attemptsRemaining, Func<Exception, bool> shouldRetry)
{
if (task.IsFaulted)
{
if (attemptsRemaining > 0 && shouldRetry(task.Exception.InnerException))
{
return taskProvider()
.ContinueWith(retryTask => RetryContinuation(retryTask, taskProvider, --attemptsRemaining, shouldRetry))
.Result;
}
else
{
// will throw AggregateException
return task.Result;
}
}
else
{
return task.Result;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment