Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yetanotherchris/389b17b5495c08384d0def5185d740a2 to your computer and use it in GitHub Desktop.
Save yetanotherchris/389b17b5495c08384d0def5185d740a2 to your computer and use it in GitHub Desktop.
Polly CircuitBreaker, Retry and Timeout configuration example for HttpClient and HttpClientFactory
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using TestCircuitBreaker.Models;
namespace TestCircuitBreaker.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IHttpClientFactory _factory;
public HomeController(ILogger<HomeController> logger, IHttpClientFactory factory)
{
_logger = logger;
_factory = factory;
}
public async Task<IActionResult> Index()
{
var client = _factory.CreateClient("localhost509");
string result = await client.GetStringAsync("/");
return Content(result);
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Polly;
using Polly.Extensions.Http;
using Polly.Timeout;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
// dotnet add package Polly.Extensions.Http
// dotnet add package Microsoft.Extensions.Http.Polly
// see: https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory
namespace TestCircuitBreaker
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging();
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>() // thrown by Polly's TimeoutPolicy if the inner execution times out
.RetryAsync(15);
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1);
var circuitPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>()
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromSeconds(20),
onBreak: (response, timeSpan) =>
{
Console.Write("broken");
},
onReset: () =>
{
Console.WriteLine("reset");
});
// Retry executes Circuit (if the circuit is open, it fails), which executes Timeout
services
.AddHttpClient("localhost509", c => c.BaseAddress = new Uri("http://localhost:509"))
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(circuitPolicy)
.AddPolicyHandler(timeoutPolicy);
services.AddControllersWithViews();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseMiddleware<ExceptionMiddleware>();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
Console.WriteLine($"================ {ex.GetType().ToString()}");
httpContext.Response.StatusCode = StatusCodes.Status226IMUsed; // something to distinguish this middleware
await httpContext.Response.WriteAsJsonAsync("{ 'a' : 1 }");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment