/// <summary> /// Processes an action with this retry policy. /// </summary> /// <param name="policy">The retry policy.</param> /// <param name="action">The async action which will return a result to process.</param> /// <param name="needThrow">A handler to check if need throw the exception without retry.</param> /// <param name="cancellationToken">The optional cancellation token.</param> /// <returns>The processing retry result.</returns> public static async Task <RetryResult <T> > ProcessAsync <T>(this IRetryPolicy policy, Func <CancellationToken, Task <T> > action, Func <Exception, Exception> needThrow, CancellationToken cancellationToken = default) { var result = new RetryResult <T>(); if (action == null) { return(result); } if (needThrow == null) { needThrow = ex => ex; } var retry = policy?.CreateInstance() ?? new InternalRetryInstance(); while (true) { try { cancellationToken.ThrowIfCancellationRequested(); var r = await action(cancellationToken); result.Success(r); return(result); } catch (Exception ex) { result.Fail(ex); ex = needThrow(ex); if (ex != null) { throw ex; } } var span = retry.Next(); if (!span.HasValue) { result.End(); return(result); } await Task.Delay(span.Value, cancellationToken); } }
/// <summary> /// Enables retry policy to process. /// </summary> /// <param name="cancellationToken">The optional cancellation token.</param> /// <returns>The processing retry result.</returns> public async Task <RetryResult> ProcessAsync(CancellationToken cancellationToken = default) { State = TaskStates.Initializing; var result = new RetryResult(); var retry = RetryPolicy?.CreateInstance() ?? new InternalRetryInstance(); State = TaskStates.Working; while (true) { try { cancellationToken.ThrowIfCancellationRequested(); } catch (OperationCanceledException) { State = TaskStates.Canceled; throw; } catch (ObjectDisposedException) { State = TaskStates.Canceled; throw; } try { await OnProcessAsync(cancellationToken); Processing?.Invoke(this, new RetryEventArgs(retry.ProcessTime)); State = TaskStates.Done; result.Success(); return(result); } catch (Exception ex) { State = TaskStates.WaitingToRetry; result.Fail(ex); try { ex = ExceptionHandler.GetException(ex); } catch (Exception) { State = TaskStates.Faulted; throw; } if (ex != null) { State = TaskStates.Faulted; throw ex; } } var span = retry.Next(); if (!span.HasValue) { State = TaskStates.Faulted; result.End(); return(result); } await Task.Delay(span.Value, cancellationToken); State = TaskStates.Retrying; } }