HttpClient 재시도 논리가 예상대로 작동하지 않음(.Net Core 3.1) (HttpClient retry logic not working as expected (.Net Core 3.1))


문제 설명

HttpClient 재시도 논리가 예상대로 작동하지 않음(.Net Core 3.1) (HttpClient retry logic not working as expected (.Net Core 3.1))

Startup.cs에는 다음 코드 줄이 있습니다.

services.AddHttpClient<CustomClientFactory>()
        .AddTransientHttpErrorPolicy(
            p => p.WaitAndRetryAsync(3, 
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 1)));

이 클래스는 외부 서비스를 호출하지만 재시도하지 않는 클래스에 해당합니다. 실패시. 폴리를 설치했습니다. 오류가 발생하지 않습니다. 단순히 실패하면 재시도하지 않는 것입니다. 제가 잘못 알고 있는 건가요?

아래는 CustomClientFactory에 대한 부분 코드입니다.

public class CustomClientFactory: ICustomClientFactory
{

    private static readonly HttpClient _httpClient;

    private IConfiguration _config;

    public CustomClientFactory(IConfiguration config)
    {
        _config = config;
    }

   // other methods
}

참조 솔루션

방법 1:

First, the AddTransientHttpErrorPolicy has been preconfigured errors to handle errors in the following categories: Network failures, http 5XX and Http 408 status code.

enter image description here

And since this Policy was configured to the CustomClientFactory, only the http request which is sent from the CustomClientFactory will use this policy, it means that if you directly using Postman to access the external service, without via the CustomClientFactory, it will not trigger this policy.

You can refer the following sample:

Prerequisites: Install the Microsoft.Extensions.Http.Polly package

Create a WeatherForecastController controller: In this controller, since there have two get method with the same route, it will show the 500 error.

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(‑20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
    [HttpGet]
    public IEnumerable<string> Get(int id)
    {
        return new string[] { "value1", "value2" };
    }
}

Then Create a TestClientFactory with the following code:

public class TestClientFactory
{
    private readonly HttpClient _httpClient;
    public TestClientFactory(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<List<WeatherForecast>> GetWeather()
    {
        _httpClient.BaseAddress = new Uri("https://localhost:5001"); 
        return await _httpClient.GetFromJsonAsync<List<WeatherForecast>>("WeatherForecast");
    }
}

And configure the retry policy in the ConfigureService method:

    public void ConfigureServices(IServiceCollection services)
    { 
        services.AddControllersWithViews();

        services.AddHttpClient<TestClientFactory>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))
        .AddTransientHttpErrorPolicy(
        p => p.WaitAndRetryAsync(3,
            retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 1)));
        //you can also use the following method.
        //.AddPolicyHandler(GetRetryPolicy()); 
    }

    //private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    //{
    //    return HttpPolicyExtensions
    //    .HandleTransientHttpError()
    //    .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(10));
    //}

Then, create a Test API controller to use the TestClientFactory:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly TestClientFactory _testClient;
    public TestController(TestClientFactory testClient)
    {
        _testClient = testClient;
    }

    [HttpGet]
    [Route("weather")]
    public async Task<IActionResult> GetWeatherAsync()
    {
        return Ok(await _testClient.GetWeather());
    }
}

After running the application, we can see that: When using the postman directly access the WeatherForecastController, the result as below:

enter image description here

When using the postman access the WeatherForecastController via the CustomClientFactory, the result like this:

enter image description here

We can see that the retry policy works and it try multiple times.

(by Riko HamblinZhi Lv)

참조 문서

  1. HttpClient retry logic not working as expected (.Net Core 3.1) (CC BY‑SA 2.5/3.0/4.0)

#asp.net-core #.net-core #C# #.net #polly






관련 질문

ASP.NET 5 프로젝트용 DNX를 선택하는 방법 (How to choose DNX for ASP.NET 5 project)

ASP.NET 5 - 프로젝트의 파일 참조(csproj와 유사한 참조 누락) (ASP.NET 5 - Referencing files in projects (missing csproj-like references))

ASP.NET 5에 OData를 등록하는 방법 (How to register OData with ASP.NET 5)

Asp.net 5 - 도커 (Asp.net 5 - Docker)

ASP.NET Core MVC에서 컨트롤러별로 데이터베이스에서 정보 읽기 (Reading information from database by controller in ASP.NET Core MVC)

이 목록에 정렬 오류가 있는 이유는 무엇입니까? (Why is there a sorting error in this list?)

foreach 루프에서 모든 데이터를 반환하는 방법 (How to return all data in foreach loop)

읽기 전용 면도기 C# asp.net의 드롭다운 목록을 만드는 방법 (how to make dropdownlistfor readonly razor c# asp.net)

.net Core: C# 코드에서 매개 변수를 전달하고 Azure 데이터 팩터리 파이프라인을 실행하는 방법은 무엇입니까? (.net Core : How to pass parameters and run Azure data factory pipeline from C# Code?)

현재 .NET SDK는 TFS 2015 빌드에서 .NET Core 3.0 대상 지정을 지원하지 않습니다. (The current .NET SDK does not support targeting .NET Core 3.0 on TFS 2015 build)

HTTP 오류 500.30 - ANCM 진행 중인 시작 실패 Asp.net-Core 3.1 (HTTP Error 500.30 - ANCM In-Process Start Failure Asp.net-Core 3.1)

System.Data.SqlClient.TdsParser' 예외가 발생했습니다: System.BadImageFormatException: 잘못된 형식의 프로그램을 로드하려고 했습니다. (System.Data.SqlClient.TdsParser' threw an exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format)







코멘트