In this example, we’ll implement the Wait and Retry and Circuit Breaker policy using .Net 6 Web API and Polly. For more details on what Circuit Breaker is, refer to the MSDN documentation.
Create a WebAPI with ValuesController in .Net 6 which will always return an Exception in the Get call.
using Microsoft.AspNetCore.Mvc;
namespace ExternalAPI.Controllers
{
[ApiController]
[Route("[controller]")]
public class ValuesController : ControllerBase
{
private readonly ILogger<ValuesController> _logger;
public ValuesController(ILogger<ValuesController> logger)
{
_logger = logger;
}
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
throw new Exception("Error");
}
}
}
Let’s call this ExternalAPI and running on https://localhost:7250/.
Create another .Net 6 WebAPI called CircuitBreaker.Demo and install Polly and Newtonsoft.json Nuget packages.
Configure Polly and HttpClient in Program.cs file as shown below:
using Polly;
using Polly.Extensions.Http;
var builder = WebApplication.CreateBuilder(args);
var httpRetryPolicy = Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt));
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddHttpClient("errorApi", c => { c.BaseAddress = new Uri("https://localhost:7250"); });
builder.Services.AddSingleton<IAsyncPolicy<HttpResponseMessage>>(httpRetryPolicy);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Now add the PollyController to call the ExternalAPI using the HttpClient:
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Polly;
namespace CircuitBreaker.Demo.Controllers
{
[ApiController]
[Route("[controller]")]
public class PollyController : ControllerBase
{
private readonly ILogger<PollyController> _logger;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IAsyncPolicy<HttpResponseMessage> _policy;
public PollyController(ILogger<PollyController> logger, IHttpClientFactory httpClientFactory, IAsyncPolicy<HttpResponseMessage> policy)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
_policy = policy;
}
[HttpGet(Name = "GetApiResult")]
public async Task<ActionResult<IEnumerable<string>>> Get()
{
var client = _httpClientFactory.CreateClient("errorApi");
var response = await _policy.ExecuteAsync(() => client.GetAsync("values"));
response.EnsureSuccessStatusCode();
return JsonConvert.DeserializeObject<string[]>(await response.Content.ReadAsStringAsync());
}
}
}
When you run both the APIs, the call to External APIs is automatically made using Wait and Retry policy after every retryAttempt number of seconds 3 times. After that, the calls are stopped as the ExternalAPI keeps giving 500 error.
CircuitBreaker example:
Now change the Http Retry Policy line in the Program.cs file to:
var httpRetryPolicy = Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.CircuitBreakerAsync(2, TimeSpan.FromSeconds(30));
The above line will open the circuit and will start giving Circuit Open Exception after 2 attempts and keep the circuit Open for 30 seconds, which means you cannot make further calls to the API for that duration. The Exception will now be shown as below:
