Esempio n. 1
0
        /// <summary>
        /// Execute a given function a number of times, based on retry configuration parameters.
        /// </summary>
        public static Task ExecuteWithRetriesAsync(
            Func <int, Task> userDefinedFunction,
            int maxNumErrorTries,
            Func <Exception, int, bool> retryExceptionFilter,
            TimeSpan maxExecutionTime,
            IBackOffProvider onErrorBackOff = null)
        {
            async Task <bool> WrapFunction(int i)
            {
                await userDefinedFunction(i);

                return(true);
            }

            return(DoExecuteWithRetriesAsync(
                       WrapFunction,
                       0,
                       0,
                       maxNumErrorTries,
                       maxExecutionTime,
                       DateTime.UtcNow,
                       null,
                       retryExceptionFilter,
                       null,
                       onErrorBackOff));
        }
Esempio n. 2
0
 /// <summary>
 /// Execute a given function a number of times, based on retry configuration parameters.
 /// </summary>
 public static Task <T> ExecuteWithRetriesAsync <T>(
     Func <int, Task <T> > userDefinedFunction,
     int maxNumErrorTries,
     Func <Exception, int, bool> retryExceptionFilter,
     TimeSpan maxExecutionTime,
     IBackOffProvider onErrorBackOff = null)
 {
     return(ExecuteWithRetriesAsync <T>(
                userDefinedFunction,
                0,
                maxNumErrorTries,
                null,
                retryExceptionFilter,
                maxExecutionTime,
                null,
                onErrorBackOff));
 }
Esempio n. 3
0
 /// <summary>
 /// Execute a given function a number of times, based on retry configuration parameters.
 /// </summary>
 /// <param name="userDefinedFunction">Function to execute</param>
 /// <param name="maxNumSuccessTries">Maximal number of successful execution attempts.
 /// ExecuteWithRetries will try to re-execute the given function again if directed so by retryValueFilter.
 /// Set to -1 for unlimited number of success retries, until retryValueFilter is satisfied.
 /// Set to 0 for only one success attempt, which will cause retryValueFilter to be ignored and the given function executed only once until first success.</param>
 /// <param name="maxNumErrorTries">Maximal number of execution attempts due to errors.
 /// Set to -1 for unlimited number of error retries, until retryExceptionFilter is satisfied.</param>
 /// <param name="retryValueFilter">Filter function to indicate if successful execution should be retied.
 /// Set to null to disable successful retries.</param>
 /// <param name="retryExceptionFilter">Filter function to indicate if error execution should be retied.
 /// Set to null to disable error retries.</param>
 /// <param name="maxExecutionTime">The maximal execution time of the ExecuteWithRetries function.</param>
 /// <param name="onSuccessBackOff">The back off provider object, which determines how much to wait between success retries.</param>
 /// <param name="onErrorBackOff">The back off provider object, which determines how much to wait between error retries.</param>
 /// <returns></returns>
 public static Task <T> ExecuteWithRetriesAsync <T>(
     Func <int, Task <T> > userDefinedFunction,
     int maxNumSuccessTries,
     int maxNumErrorTries,
     Func <T, int, bool> retryValueFilter,
     Func <Exception, int, bool> retryExceptionFilter,
     TimeSpan maxExecutionTime         = default,
     IBackOffProvider onSuccessBackOff = null,
     IBackOffProvider onErrorBackOff   = null)
 {
     return(DoExecuteWithRetriesAsync <T>(
                userDefinedFunction,
                0,
                maxNumSuccessTries,
                maxNumErrorTries,
                maxExecutionTime,
                DateTime.UtcNow,
                retryValueFilter,
                retryExceptionFilter,
                onSuccessBackOff,
                onErrorBackOff));
 }
Esempio n. 4
0
        private static async Task <T> DoExecuteWithRetriesAsync <T>(
            Func <int, Task <T> > userDefinedFunction,
            int callCounter,
            int maxNumSuccessTries,
            int maxNumErrorTries,
            TimeSpan maxExecutionTime,
            DateTime startExecutionTime,
            Func <T, int, bool> retryValueFilter             = null,
            Func <Exception, int, bool> retryExceptionFilter = null,
            IBackOffProvider onSuccessBackOff = null,
            IBackOffProvider onErrorBackOff   = null)
        {
            onSuccessBackOff ??= DefaultBackOffProvider;
            onErrorBackOff ??= DefaultBackOffProvider;

            var result = default(T);
            ExceptionDispatchInfo lastExceptionInfo = null;
            bool needRetry;

            do
            {
                needRetry = false;

                if (maxExecutionTime != InfiniteTimespan &&
                    maxExecutionTime != default)
                {
                    var now = DateTime.UtcNow;
                    if (now - startExecutionTime > maxExecutionTime)
                    {
                        if (lastExceptionInfo == null)
                        {
                            throw new TimeoutException(
                                      $"ExecuteWithRetries has exceeded its max execution time of {maxExecutionTime}. Now is {LogFormatter.PrintDate(now)}, started at {LogFormatter.PrintDate(startExecutionTime)}, passed {now - startExecutionTime}");
                        }

                        lastExceptionInfo.Throw();
                    }
                }

                var counter = callCounter;

                try
                {
                    callCounter++;
                    result = await userDefinedFunction(counter);

                    lastExceptionInfo = null;

                    if (callCounter < maxNumSuccessTries ||
                        maxNumSuccessTries == InfiniteRetries) // -1 for infinite retries
                    {
                        if (retryValueFilter != null)
                        {
                            needRetry = retryValueFilter(result, counter);
                        }
                    }

                    if (needRetry)
                    {
                        var delay = onSuccessBackOff?.Next(counter);

                        if (delay.HasValue)
                        {
                            await Task.Delay(delay.Value);
                        }
                    }
                }
                catch (Exception exc)
                {
                    needRetry = false;

                    if (callCounter < maxNumErrorTries ||
                        maxNumErrorTries == InfiniteRetries)
                    {
                        if (retryExceptionFilter != null)
                        {
                            needRetry = retryExceptionFilter(exc, counter);
                        }
                    }

                    if (!needRetry)
                    {
                        throw;
                    }

                    lastExceptionInfo = ExceptionDispatchInfo.Capture(exc);

                    var delay = onErrorBackOff?.Next(counter);

                    if (delay.HasValue)
                    {
                        await Task.Delay(delay.Value);
                    }
                }
            } while (needRetry);

            return(result);
        }