Example #1
0
        public static async Task <T> WithRetriesAsync <T>(Func <Task <T> > action, int maxAttempts = 5, TimeSpan?retryInterval = null, CancellationToken cancellationToken = default, ILogger logger = null)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            int attempts           = 1;
            var startTime          = SystemClock.UtcNow;
            int currentBackoffTime = _defaultBackoffIntervals[0];

            if (retryInterval != null)
            {
                currentBackoffTime = (int)retryInterval.Value.TotalMilliseconds;
            }

            do
            {
                if (attempts > 1 && logger != null && logger.IsEnabled(LogLevel.Information))
                {
                    logger.LogInformation("Retrying {Attempts} attempt after {Delay:g}...", attempts.ToOrdinal(), SystemClock.UtcNow.Subtract(startTime));
                }

                try {
                    return(await action().AnyContext());
                } catch (Exception ex) {
                    if (attempts >= maxAttempts)
                    {
                        throw;
                    }

                    if (logger != null && logger.IsEnabled(LogLevel.Error))
                    {
                        logger.LogError(ex, "Retry error: {Message}", ex.Message);
                    }

                    await SystemClock.SleepSafeAsync(currentBackoffTime, cancellationToken).AnyContext();
                }

                if (retryInterval == null)
                {
                    currentBackoffTime = _defaultBackoffIntervals[Math.Min(attempts, _defaultBackoffIntervals.Length - 1)];
                }
                attempts++;
            } while (attempts <= maxAttempts && !cancellationToken.IsCancellationRequested);

            throw new TaskCanceledException("Should not get here.");
        }