public static async Task <T> RetryAsync <T>(Func <Task <T> > asyncFunc, CancellationToken cancellationToken, IRetryStrategy strategy, IRetryPolicy policy, bool continueOnCapturedContext) { do { Exception exception; try { return(await asyncFunc().ConfigureAwait(continueOnCapturedContext)); } catch (Exception ex) { exception = ex; } var delay = strategy.PrepareToRetry(exception); if (!WillRetry(exception, cancellationToken, strategy, policy)) { throw exception; } strategy.OnRetrying(new RetryEventArgs(exception, delay)); if (delay != TimeSpan.Zero) { if (SleepService != null) { SleepService.Sleep(delay); } } }while (true); }
public static T Retry <T>(Func <T> func, CancellationToken cancellationToken, IRetryStrategy strategy, IRetryPolicy policy) { do { try { return(func()); } catch (Exception exception) { var delay = strategy.PrepareToRetry(exception); if (!WillRetry(exception, cancellationToken, strategy, policy)) { throw; } strategy.OnRetrying(new RetryEventArgs(exception, delay)); if (delay != TimeSpan.Zero) { if (SleepService != null) { SleepService.Sleep(delay); } } } }while (true); }
public async Task <Boolean> PrepareToRetry(Exception exception, CancellationToken cancellationToken) { using (List <IRetryStrategy> .Enumerator strategiesEnumerator = _retryStrategies.GetEnumerator()) { Boolean canRetry = true; while (canRetry && strategiesEnumerator.MoveNext()) { IRetryStrategy strategy = strategiesEnumerator.Current; canRetry = await strategy.PrepareToRetry(exception, cancellationToken); } return(canRetry); } }
/// <summary> /// Retries an asynchronous operation with cancellation. /// </summary> /// <param name="asyncFunc">The asynchronous function to retry.</param> /// <param name="cancellationToken">The token with which to signal cancellation.</param> /// <param name="strategy">The retry strategy.</param> /// <param name="policy">The retry policy.</param> /// <param name="continueOnCapturedContext">Whether to continue on the captured context.</param> /// <returns>A task which completes when the operation completes.</returns> public static async Task RetryAsync(Func <Task> asyncFunc, CancellationToken cancellationToken, IRetryStrategy strategy, IRetryPolicy policy, bool continueOnCapturedContext) { if (asyncFunc is null) { throw new ArgumentNullException(nameof(asyncFunc)); } if (strategy is null) { throw new ArgumentNullException(nameof(strategy)); } if (policy is null) { throw new ArgumentNullException(nameof(policy)); } while (true) { Exception exception; try { await asyncFunc().ConfigureAwait(continueOnCapturedContext); return; } catch (Exception ex) { exception = ex; } TimeSpan delay = strategy.PrepareToRetry(exception); if (!WillRetry(exception, cancellationToken, strategy, policy)) { throw exception; } strategy.OnRetrying(new RetryEventArgs(exception, delay)); if (delay != TimeSpan.Zero) { await SleepService.Instance.SleepAsync(delay).ConfigureAwait(continueOnCapturedContext); } } }
/// <summary> /// Handles retrying a given task. /// </summary> /// <param name="task">The task that is currently executing.</param> /// <param name="createTask">A function that can create a new task to retry the operation.</param> /// <param name="strategy">The retry strategy.</param> /// <param name="policy">The retry policy.</param> /// <returns>A new task which is retrying the existing task, or the original task if retry is not required.</returns> /// <remarks> /// <para> /// If the task completed successfully, then retry is not required and the original task is returned. /// </para> /// <para> /// It the task failed, then this method uses the strategy to determine whether it will retry based on the exception on the original task. /// If it will retry, it raises the <see cref="IRetryStrategy.Retrying"/> event, then delays for the calculated time using the Sleep service. /// It then creates a new task using the <c>createTask</c> function provided, and runs the task synchronously. /// </para> /// </remarks> internal static Task HandleRetry(Task task, Func <Task> createTask, IRetryStrategy strategy, IRetryPolicy policy) { if (task is null) { throw new ArgumentNullException(nameof(task)); } if (createTask is null) { throw new ArgumentNullException(nameof(createTask)); } if (strategy is null) { throw new ArgumentNullException(nameof(strategy)); } if (policy is null) { throw new ArgumentNullException(nameof(policy)); } while (task.Exception != null) { TimeSpan delay = strategy.PrepareToRetry(task.Exception); if (!WillRetry(task, strategy, policy)) { break; } strategy.OnRetrying(new RetryEventArgs(task.Exception, delay)); if (delay != TimeSpan.Zero) { SleepService.Instance.Sleep(delay); } task = createTask(); task.RunSynchronously(); } return(task); }
/// <summary> /// Retries an operation with cancellation. /// </summary> /// <param name="func">The operatoin to retry.</param> /// <param name="cancellationToken">The token with which cancellation is signalled.</param> /// <param name="strategy">The retry strategy.</param> /// <param name="policy">The retry policy.</param> /// <remarks>This function does not continue on the captured context. See the overload if you want to override this default behaviour.</remarks> public static void Retry(Action func, CancellationToken cancellationToken, IRetryStrategy strategy, IRetryPolicy policy) { if (func is null) { throw new ArgumentNullException(nameof(func)); } if (strategy is null) { throw new ArgumentNullException(nameof(strategy)); } if (policy is null) { throw new ArgumentNullException(nameof(policy)); } while (true) { try { func(); return; } catch (Exception exception) { TimeSpan delay = strategy.PrepareToRetry(exception); if (!WillRetry(exception, cancellationToken, strategy, policy)) { throw; } strategy.OnRetrying(new RetryEventArgs(exception, delay)); if (delay != TimeSpan.Zero) { SleepService.Instance.Sleep(delay); } } } }
public static async Task Retry(this Func <Task> asyncFunc, IRetryStrategy strategy, CancellationToken cancellationToken = default) { do { try { await asyncFunc(); return; } catch (Exception ex) { Boolean canRetry = await strategy.PrepareToRetry(ex, cancellationToken); if (!canRetry || cancellationToken.IsCancellationRequested) { throw; } } }while (true); }