public static async Task AttemptAsync( this IRetry policy, Func <int, Task> action, Action <Exception, int, TimeSpan> onException, Action <Exception, int> onFinalException, CancellationToken cancellationToken) { var timer = new Stopwatch(); timer.Start(); for (var attempt = 0; !cancellationToken.IsCancellationRequested; attempt++) { cancellationToken.ThrowIfCancellationRequested(); try { await action(attempt).ConfigureAwait(false); // reset attempt when successful attempt = -1; timer.Restart(); } catch (Exception ex) { if (attempt == 0) // first failure { timer.Restart(); } await policy.HandleErrorAndDelayAsync(onException, onFinalException, attempt, timer, ex, cancellationToken).ConfigureAwait(false); } } }
public static async Task <T> AttemptAsync <T>( this IRetry policy, Func <int, Stopwatch, Task <RetryAttempt <T> > > action, Action <int, TimeSpan> onRetry, Action <int> onFinal, Action <Exception, int, TimeSpan> onException, Action <Exception, int> onFinalException, CancellationToken cancellationToken) { var timer = new Stopwatch(); timer.Start(); for (var attempt = 0;; attempt++) { cancellationToken.ThrowIfCancellationRequested(); try { var response = await action(attempt, timer).ConfigureAwait(false); if (response.IsSuccessful) { return(response.Value); } var retryDelay = policy.RetryDelay(attempt, timer.Elapsed); if (retryDelay.HasValue) { onRetry?.Invoke(attempt, retryDelay.Value); await Task.Delay(retryDelay.Value, cancellationToken).ConfigureAwait(false); } else { onFinal?.Invoke(attempt); return(response.Value); } } catch (Exception ex) { await policy.HandleErrorAndDelayAsync(onException, onFinalException, attempt, timer, ex, cancellationToken).ConfigureAwait(false);; } } }