C# tutorials > Frameworks and Libraries > Other Important Libraries > Polly for resilience and fault handling (retries, circuit breaker)
Polly for resilience and fault handling (retries, circuit breaker)
Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, and Fallback in a fluent and thread-safe manner. It's invaluable for building applications that can gracefully handle failures, network hiccups, and other common issues in distributed systems. This tutorial provides practical examples of using Polly to improve the robustness of your C# applications.
Installation
Before you can use Polly, you need to install it from NuGet. Open the NuGet Package Manager Console or the NuGet Package Manager UI in Visual Studio and run the following command:
Install-Package Polly
Basic Retry Policy
This code demonstrates a basic retry policy that attempts to execute an operation up to 3 times if it encounters an HttpRequestException
. The Handle
specifies the type of exception to handle. The RetryAsync(3, ...)
configures the policy to retry up to 3 times, logging each retry attempt. The ExecuteAsync
method wraps the code that might fail.
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class RetryExample
{
public static async Task Run()
{
var retryPolicy = Policy
.Handle<HttpRequestException>()
.RetryAsync(3, (exception, retryCount) =>
{
Console.WriteLine($"Retry {retryCount} due to: {exception.Message}");
});
try
{
await retryPolicy.ExecuteAsync(async () =>
{
// Simulate an HTTP request that might fail
HttpResponseMessage response = await SimulateHttpRequest();
response.EnsureSuccessStatusCode(); // Throw exception for bad status codes
Console.WriteLine("Request successful!");
});
}
catch (Exception ex)
{
Console.WriteLine($"Request failed after multiple retries: {ex.Message}");
}
}
private static async Task<HttpResponseMessage> SimulateHttpRequest()
{
// Simulate a failing request on the first two attempts
if (DateTime.Now.Second % 5 == 0 || DateTime.Now.Second % 5 == 1)
{
throw new HttpRequestException("Simulated network error.");
}
// Simulate a successful request
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
}
Explanation of Retry Policy Components
retryCount
). The onRetry
delegate is executed before each retry attempt, allowing you to log or perform other actions.
Circuit Breaker Policy
This code demonstrates a circuit breaker policy. After two consecutive HttpRequestException
failures, the circuit will open for 30 seconds, preventing further requests. The CircuitBreakerAsync(2, TimeSpan.FromSeconds(30), ...)
configures this behavior. The policy transitions through three states: Closed (normal operation), Open (requests blocked), and Half-Open (attempting to recover). The provided delegates are executed during each state transition. The OnBreak
delegate will be executed when the circuit transitions from Closed to Open. The OnHalfOpen
delegate will be executed when the circuit transitions from Open to Half-Open. The OnReset
delegate will be executed when the circuit transitions from Half-Open to Closed.
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class CircuitBreakerExample
{
public static async Task Run()
{
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.CircuitBreakerAsync(2, TimeSpan.FromSeconds(30), (exception, timespan) =>
{
Console.WriteLine($"Circuit broken for {timespan.TotalSeconds} seconds due to: {exception.Message}");
},
() =>
{
Console.WriteLine("Circuit half-open. Attempting to recover...");
},
() =>
{
Console.WriteLine("Circuit reset. Normal operation resumed.");
});
for (int i = 0; i < 5; i++)
{
try
{
await circuitBreakerPolicy.ExecuteAsync(async () =>
{
HttpResponseMessage response = await SimulateHttpRequest();
response.EnsureSuccessStatusCode();
Console.WriteLine("Request successful!");
});
}
catch (Exception ex)
{
Console.WriteLine($"Request failed: {ex.Message}");
}
await Task.Delay(1000); // Wait for 1 second between requests
}
}
private static async Task<HttpResponseMessage> SimulateHttpRequest()
{
// Simulate a failing request for the first few attempts
if (DateTime.Now.Second % 5 == 0 || DateTime.Now.Second % 5 == 1)
{
throw new HttpRequestException("Simulated network error.");
}
// Simulate a successful request
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
}
Explanation of Circuit Breaker Policy Components
handledEventsAllowedBeforeBreaking
specifies how many consecutive exceptions of the handled type are allowed before the circuit opens. durationOfBreak
specifies how long the circuit remains open. onBreak
is executed when the circuit breaks, onReset
when it resets, and onHalfOpen
when it enters the half-open state.
Real-Life Use Case Section
Imagine your application interacts with a third-party API that is sometimes unreliable. Without resilience, your application might experience cascading failures. Using Polly, you can implement a retry policy to automatically retry failed requests, potentially mitigating temporary network issues or server overloads. You can also use a circuit breaker policy to prevent your application from overwhelming the third-party API with requests when it is already unavailable, giving it time to recover. Polly can be used in conjunction with HttpClientFactory to manage HttpClient lifecycle. For example, Polly can be used to configure retry policies for HTTP requests managed by HttpClientFactory.
Best Practices
Interview Tip
Be prepared to discuss the different types of resilience policies (retry, circuit breaker, timeout, fallback) and when each is most appropriate. Explain how Polly helps improve the robustness of applications by gracefully handling failures. Explain how to use policies with HttpClientFactory. Be ready to show example code implementing these policies. Be aware of different policies strategies like Timeout or Fallback. Be able to explain exponential backoff.
When to use them
Memory footprint
Polly itself has a relatively small memory footprint. However, the memory usage depends on the complexity and configuration of your policies. For example, policies with long retry delays or large numbers of retries might consume more memory. It's generally not a significant concern, but it's good to be aware of it, especially in memory-constrained environments.
Alternatives
Pros
Cons
FAQ
-
What is the difference between Retry and Circuit Breaker?
The Retry policy attempts to re-execute an operation if it fails. It's suitable for transient faults. The Circuit Breaker policy prevents an operation from being executed if it has failed repeatedly. It's designed to protect against prolonged outages and cascading failures. -
How do I combine multiple Polly policies?
You can nest policies using theWrapAsync
method. For example, you can wrap a Retry policy around a Circuit Breaker policy to first retry a failing operation and then, if it continues to fail, open the circuit breaker to prevent further attempts. -
How do I test my Polly policies?
You can use mocking frameworks to simulate failures and verify that your Polly policies are behaving as expected. You can also use integration tests to test the policies against real services.