/// <summary> /// Initializes a new instance of the 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 retry strategy to use for this retry policy.</param> public RetryPolicy(ITransientErrorDetectionStrategy errorDetectionStrategy, RetryStrategy retryStrategy) { 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 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 representing the executable action which returns the result of type R.</param> /// <returns>The result from the action.</returns> public async virtual Task <TResult> ExecuteAction <TResult>(Func <Task <TResult> > func) { int retryCount = 0; TimeSpan delay = TimeSpan.Zero; Exception lastError; var shouldRetry = RetryStrategy.GetShouldRetry(); for (; ;) { lastError = null; try { return(await func().ConfigureAwait(false)); } catch (Exception ex) { lastError = ex; if (!(ErrorDetectionStrategy.IsTransient(lastError) && shouldRetry(retryCount++, lastError, out delay))) { throw; } } // Perform an extra check in the delay interval. Should prevent from accidentally ending up with the value of -1 that will block a thread indefinitely. // In addition, any other negative numbers will cause an ArgumentOutOfRangeException fault that will be thrown by Thread.Sleep. if (delay.TotalMilliseconds < 0) { delay = TimeSpan.Zero; } OnRetrying(retryCount, lastError, delay); if (retryCount > 1 || !RetryStrategy.FastFirstRetry) { await Task.Delay(delay).ConfigureAwait(false); } } }