Skip to content

Instantly share code, notes, and snippets.

@eulerfx
Created March 22, 2012 19:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eulerfx/2161819 to your computer and use it in GitHub Desktop.
Save eulerfx/2161819 to your computer and use it in GitHub Desktop.
TPL retry logic
/// <summary>
/// Utility methods for <see cref="System.Threading.Tasks.Task"/>.
/// </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>
public static Task<TResult> Retry<TResult>(Func<Task<TResult>> taskProvider, int maxAttemps, Func<Exception, bool> shouldRetry = null)
{
Require.NotNull(taskProvider);
Require.Positive(maxAttemps, "maxAttemps");
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