Saturday, October 18, 2025

πŸ§ͺ Practical Example — Implementing Resilience in .NET Core Using Polly

 πŸ—️ Scenario

Let’s say we have a microservice called OrderService that needs to call another service — PaymentService — through an HTTP API.
We want to make sure our OrderService:

  • Retries if the call fails (Retry Pattern)

  • Stops repeated failing calls (Circuit Breaker Pattern)

  • Times out long requests (Timeout Pattern)

  • Returns fallback data if all else fails (Fallback Pattern)


🧰 Step 1: Install Required Package

Run this command in your OrderService project:

dotnet add package Polly dotnet add package Microsoft.Extensions.Http.Polly

⚙️ Step 2: Configure Resilience Policies in Program.cs

using Polly; using Polly.Extensions.Http; var builder = WebApplication.CreateBuilder(args); // Define resilience policies var retryPolicy = HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); // exponential backoff var circuitBreakerPolicy = HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); // break after 5 failures var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(3); // 3-second timeout // Add HttpClient with resilience policies builder.Services.AddHttpClient("PaymentServiceClient", client => { client.BaseAddress = new Uri("https://payments.example.com/api/"); }) .AddPolicyHandler(retryPolicy) .AddPolicyHandler(circuitBreakerPolicy) .AddPolicyHandler(timeoutPolicy); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run();

πŸ’‘ Step 3: Use HttpClient in Controller

using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/[controller]")] public class OrderController : ControllerBase { private readonly HttpClient _httpClient; public OrderController(IHttpClientFactory httpClientFactory) { _httpClient = httpClientFactory.CreateClient("PaymentServiceClient"); } [HttpPost("create")] public async Task<IActionResult> CreateOrder([FromBody] object order) { try { var response = await _httpClient.PostAsJsonAsync("process", order); if (response.IsSuccessStatusCode) return Ok("Order placed successfully!"); return StatusCode((int)response.StatusCode, "Payment service failed."); } catch (BrokenCircuitException) { // Circuit breaker is open, fallback response return StatusCode(503, "Payment service temporarily unavailable. Try again later."); } catch (Exception ex) { // Fallback or logging return StatusCode(500, $"Unexpected error: {ex.Message}"); } } }

πŸ” Step 4: Add Health Check for Kubernetes or Azure

Add in Program.cs:

builder.Services.AddHealthChecks(); app.MapHealthChecks("/health");

✅ This allows Kubernetes or Azure App Service to detect and restart unhealthy instances automatically.


πŸ“Š Step 5: Add Observability (Optional)

Integrate Application Insights, Serilog, or ELK Stack to monitor:

  • Retry attempts

  • Circuit breaker states

  • Timeout events

This helps detect performance or availability issues early.


🧠 Output Behavior Summary

Failure TypePattern TriggeredSystem Reaction
Temporary network errorRetryAutomatically retries
Persistent downstream failureCircuit BreakerBlocks further calls temporarily
Long responseTimeoutCancels request after 3 seconds
Service completely downFallbackReturns cached/default message
Pod unhealthyHealth CheckAuto restarted by Kubernetes

πŸš€ Result

With these configurations:

  • Your microservices become self-healing.

  • You prevent cascading failures.

  • The system delivers consistent performance and high availability.

Pro Tip: Combine Polly with Serilog for logging and OpenTelemetry for tracing to create a fully observable resilient microservice system.

No comments:

Blog Archive

Don't Copy

Protected by Copyscape Online Plagiarism Checker

Pages