private Task <TResult> ExecuteAsyncContinueWith(Task <TResult> runningTask) { if (!runningTask.IsFaulted || _cancellationToken.IsCancellationRequested) { return(runningTask); } Exception lastError = runningTask.Exception.InnerException; if (!(_isTransient(lastError)) || lastError is RetryLimitExceededException) { // if not transient, return the faulted running task. return(runningTask); } RetryCondition condition = _shouldRetryHandler(_retryCount++, lastError); if (!condition.RetryAllowed) { return(runningTask); } TimeSpan delay = condition.DelayBeforeRetry; // Perform an extra check in the delay interval. if (delay < TimeSpan.Zero) { delay = TimeSpan.Zero; } _onRetrying(_retryCount, lastError, delay); _previousTask = runningTask; if (delay > TimeSpan.Zero && (_retryCount > 1 || !_fastFirstRetry)) { return(Task.Delay(delay) .ContinueWith <Task <TResult> >(ExecuteAsyncImpl, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default) .Unwrap()); } return(ExecuteAsyncImpl(null)); }
public virtual TResult ExecuteAction <TResult>(Func <TResult> func) { Guard.ArgumentNotNull(func, "func"); int retryCount = 0; TimeSpan delay = TimeSpan.Zero; Exception lastError; var shouldRetry = this.RetryStrategy.GetShouldRetryHandler(); for (;;) { lastError = null; try { return(func()); } #pragma warning disable 0618 catch (RetryLimitExceededException limitExceededEx) #pragma warning restore 0618 { // The user code can throw a RetryLimitExceededException to force the exit from the retry loop. // The RetryLimitExceeded exception can have an inner exception attached to it. This is the exception // which we will have to throw up the stack so that callers can handle it. if (limitExceededEx.InnerException != null) { throw limitExceededEx.InnerException; } else { return(default(TResult)); } } catch (Exception ex) { lastError = ex; if (!(this.ErrorDetectionStrategy.IsTransient(lastError))) { throw; } RetryCondition condition = shouldRetry(retryCount++, lastError); if (!condition.RetryAllowed) { throw; } delay = condition.DelayBeforeRetry; } // 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; } this.OnRetrying(retryCount, lastError, delay); if (retryCount > 1 || !this.RetryStrategy.FastFirstRetry) { Task.Delay(delay).Wait(); } } }