Last active
January 12, 2016 19:07
-
-
Save dealproc/5baeedc06142af832f0a to your computer and use it in GitHub Desktop.
Retry logic for tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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