File: Common\RetryHelper.cs
Web Access
Project: src\src\Hosting\Server.IntegrationTesting\src\Microsoft.AspNetCore.Server.IntegrationTesting.csproj (Microsoft.AspNetCore.Server.IntegrationTesting)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Net;
using System.Net.Http;
using Microsoft.Extensions.Logging;
 
namespace Microsoft.AspNetCore.Server.IntegrationTesting;
 
public class RetryHelper
{
    /// <summary>
    /// Retries every 1 sec for 60 times by default.
    /// </summary>
    /// <param name="retryBlock"></param>
    /// <param name="logger"></param>
    /// <param name="cancellationToken"></param>
    /// <param name="retryCount"></param>
    public static async Task<HttpResponseMessage> RetryRequest(
        Func<Task<HttpResponseMessage>> retryBlock,
        ILogger logger,
        CancellationToken cancellationToken = default,
        int retryCount = 60)
    {
        for (var retry = 0; retry < retryCount; retry++)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                logger.LogInformation("Failed to connect, retry canceled.");
                throw new OperationCanceledException("Failed to connect, retry canceled.", cancellationToken);
            }
 
            try
            {
                logger.LogWarning("Retry count {retryCount}..", retry + 1);
                var response = await retryBlock().ConfigureAwait(false);
 
                if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
                {
                    // Automatically retry on 503. May be application is still booting.
                    logger.LogWarning("Retrying a service unavailable error.");
                    continue;
                }
 
                return response; // Went through successfully
            }
            catch (Exception exception)
            {
                if (retry == retryCount - 1)
                {
                    logger.LogError(0, exception, "Failed to connect, retry limit exceeded.");
                    throw;
                }
                else
                {
                    if (exception is HttpRequestException || exception is WebException)
                    {
                        logger.LogWarning("Failed to complete the request : {0}.", exception.Message);
                        await Task.Delay(1 * 1000); //Wait for a while before retry.
                    }
                }
            }
        }
 
        logger.LogInformation("Failed to connect, retry limit exceeded.");
        throw new OperationCanceledException("Failed to connect, retry limit exceeded.");
    }
 
    public static void RetryOperation(
        Action retryBlock,
        Action<Exception> exceptionBlock,
        int retryCount = 3,
        int retryDelayMilliseconds = 0)
    {
        for (var retry = 0; retry < retryCount; ++retry)
        {
            try
            {
                retryBlock();
                break;
            }
            catch (Exception exception)
            {
                exceptionBlock(exception);
            }
 
            Thread.Sleep(retryDelayMilliseconds);
        }
    }
}