/// <summary> /// Repeatedly executes the specified asynchronous task while it satisfies the current retry policy. /// </summary> /// <param name="taskFunc">A function that returns a started task (also known as "hot" task).</param> /// <param name="cancellationToken">The token used to cancel the retry operation. This token does not cancel the execution of the asynchronous task.</param> /// <returns> /// Returns a task that will run to completion if the original task completes successfully (either the /// first time or after retrying transient failures). If the task fails with a non-transient error or /// the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. /// </returns> public Task <TResult> ExecuteAsync <TResult>(Func <Task <TResult> > taskFunc, CancellationToken cancellationToken) { if (taskFunc == null) { throw new ArgumentNullException(nameof(taskFunc)); } return(new AsyncExecution <TResult>(taskFunc, RetryStrategy.GetShouldRetry(), new Func <Exception, bool>(ErrorDetectionStrategy.IsTransient), new Action <int, Exception, TimeSpan>(OnRetrying), RetryStrategy.FastFirstRetry, cancellationToken).ExecuteAsync()); }
/// <summary> /// Initializes a new instance of the <see cref="RetryPolicy" /> class with the specified number of retry attempts and parameters defining the progressive delay between retries. /// </summary> /// <param name="errorDetectionStrategy">The <see cref="ITransientErrorDetectionStrategy" /> that is responsible for detecting transient conditions.</param> /// <param name="retryStrategy">The strategy to use for this retry policy.</param> public RetryPolicy(ITransientErrorDetectionStrategy errorDetectionStrategy, RetryStrategy retryStrategy) { Guard.ArgumentNotNull(errorDetectionStrategy, "errorDetectionStrategy"); Guard.ArgumentNotNull(retryStrategy, "retryPolicy"); ErrorDetectionStrategy = errorDetectionStrategy; if (errorDetectionStrategy == null) { throw new InvalidOperationException("The error detection strategy type must implement the ITransientErrorDetectionStrategy interface."); } RetryStrategy = retryStrategy; }
/// <summary> /// Repetitively executes the specified asynchronous task while it satisfies the current retry policy. /// </summary> /// <param name="taskAction">A function that returns a started task (also known as "hot" task).</param> /// <param name="cancellationToken">The token used to cancel the retry operation. This token does not cancel the execution /// of the asynchronous task.</param> /// <returns> /// Returns a task that will run to completion if the original task completes successfully (either the /// first time or after retrying transient failures). If the task fails with a non-transient error or /// the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. /// </returns> public Task RunWithRetryAsync(Func <Task> taskAction, CancellationToken cancellationToken = default) { return(taskAction == null ? throw new ArgumentNullException(nameof(taskAction)) : RunWithRetryAsync( taskAction, RetryStrategy.GetShouldRetry(), new Func <Exception, bool>(ErrorDetectionStrategy.IsTransient), new Action <int, Exception, TimeSpan>(OnRetrying), RetryStrategy.FastFirstRetry, cancellationToken)); }
/// <summary> /// Repetitively executes the specified action while it satisfies the current retry policy. /// </summary> /// <typeparam name="TResult">The type of result expected from the executable action.</typeparam> /// <param name="func">A delegate that represents the executable action that returns the result of type <typeparamref name="TResult" />.</param> /// <returns>The result from the action.</returns> public virtual TResult ExecuteAction <TResult>(Func <TResult> func) { Guard.ArgumentNotNull(func, "func"); int num = 0; ShouldRetry shouldRetry = RetryStrategy.GetShouldRetry(); TResult result; while (true) { Exception ex; TimeSpan zero; try { result = func(); break; } catch (RetryLimitExceededException ex2) { if (ex2.InnerException != null) { throw ex2.InnerException; } result = default; break; } catch (Exception ex3) { ex = ex3; if (!ErrorDetectionStrategy.IsTransient(ex) || !shouldRetry(num++, ex, out zero)) { throw; } } if (zero.TotalMilliseconds < 0.0) { zero = TimeSpan.Zero; } OnRetrying(num, ex, zero); if (num > 1 || !RetryStrategy.FastFirstRetry) { Task.Delay(zero).Wait(); } } return(result); }