Consider the scenario in which you send a request to an external API in your application using HttpClient. If an external service becomes unavailable, requests sent to your application that you send to this API via HttpClient will be delayed and you may receive an Internal Server Error or Request Timeout Error. If the number of users in your application is large, this operation will be performed per user and all users will be faced with a delay of a few seconds. To solve this problem, we can use Circuit Breaker, so that if the desired service becomes unavailable, we will not send that request to an external API. To implement this scenario, we create a test project of the type Asp.Net Core Web Application. Next, you need to install Microsoft.Extensions.Http.Polly package to implement the Circuit Breaker operation.

Then we create a class to send the request to the desired service:

public class SomeService : ISomeService
{
    private readonly HttpClient _httpClient;

    public SomeService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> DoSomething(CancellationToken cancellationToken)
    {
        string result = string.Empty;
        try
        {
             await _httpClient.GetAsync("notfounduri", cancellationToken);
            result = "Ok";
        }
        catch (Polly.CircuitBreaker.BrokenCircuitException)
        {
            result = "Service is unavailable. please try again";
        }
        return result;
    }
}

In the DoSomething method, we send a request to an address that does not exist and actually returns a 404 error.

Relevant controller:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly ISomeService _someService;

    public TestController(ISomeService someService)
    {
        _someService = someService;
    }
    [HttpGet]
    public async Task<IActionResult> Get(CancellationToken cancellationToken)
    {
        var result = await _someService.DoSomething(cancellationToken);
        return Ok(result);
    }
}

Then in the Startup class, we create a scenario for error 404:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddScoped<ISomeService, SomeService>();
    services.AddHttpClient<ISomeService, SomeService>(options=>
    {
        options.BaseAddress = new Uri("https://stackoverflow.com");
    })
    .AddPolicyHandler(GetCircuitBreakerPolicy())
    .AddPolicyHandler(GetRetryPolicy());
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
                   .HandleTransientHttpError()
                   .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
                   .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
    return HttpPolicyExtensions
                   .HandleTransientHttpError()
                   .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
                   .CircuitBreakerAsync(2, TimeSpan.FromSeconds(30));
}

In the AddHttpClient method, we specify the BaseAddress value that sends the request to the Stackoverflow site. 

The GetRetryPolicy method specifies that if the sent request receives a 404 error, it automatically sends the request 2 more times, and the delay between the first attempt and the next attempt is specified as Math.Pow (2, retryAttempt). That is, if an error occurs in the first request, it will send the next request again after the time (2 to the power (number of attempts to send the request)). This means that the delay between the submitted requests is more and more. 

In the GetCircuitBreakerPolicy method, we specified that if this scenario was executed twice, that is, twice the API for sending the request to the "/api/test" service was called (not the number of retries related to Polly) and each time it received a 404 error, up to 30 seconds It then does not send a request to the Stackoverflow site and issues a Polly.CircuitBreaker.BrokenCircuitException error. This will cause only the first two requests with a 404 delay, and the "Service is unavailable. Please try again" error will be returned to the user within 30 seconds.

Of course, it is better to implement this operation for 500 errors, but we used 404 error to implement the relevant example.

References:

;)

Powered by Froala Editor

Comments