Polly is an Open Source library for .Net that allows implementing certain resilience patterns and exception management/recovery in .Net applications.
When dealing with processes that are prone to throwing exceptions there are several patterns or strategies we can follow to manage behavior in case of an error. However, implementing these patterns requires time and code.
Polly simplifies the process by allowing us to implement patterns like Retry, Timeout, or Circuit-breaker in a robust and very simple way through its Fluent syntax.
The patterns we can implement with Polly are:
- Retry: Attempts to execute the process N times or indefinitely.
- Circuit-breaker: When several failures occur, disables the process for a period of time.
- Timeout: Attempts to execute a process for a certain amount of time.
- Fallback: Executes a process in case of an error (similar to try-catch).
- Bulkhead: Limits the number of processes that can run in parallel.
- Cache: Avoids executing a process if it has already been executed before.
- PolicyWrap: Combines several of the previous rules.
Each of these patterns has numerous parameters and options to adapt them to our needs. For more information about them, consult the abundant documentation available on the project’s website https://github.com/App-vNext/Polly
Polly is a library primarily designed for Web processes. So you’ll see many available examples focus on topics related to Http requests. However, Polly can be useful in a wide variety of situations and projects even if they are not at all related to communication.
To illustrate this, let’s look at a few small examples of the library’s use and operation. To do this, we simply create a console application and add Polly via the Nuget package manager.
Retry Pattern
The Retry pattern simply attempts to repeat the action if an exception occurs.
using Polly;
sing Polly.Timeout;
using System;
using System.Diagnostics;
namespace TestPolly
{
class Program
{
static void Main(string[] args)
{
testRetry();
}
static void testRetry()
{
try
{
Policy
.Handle<Exception>()
.Retry(3)
.Execute(RetrySampleMethod);
}
catch (Exception)
{
Console.WriteLine("Retry exceed");
}
Console.WriteLine("Finish");
Console.ReadLine();
}
static int counter = 0;
[DebuggerNonUserCode]
static void RetrySampleMethod()
{
Console.WriteLine(counter);
counter++;
throw new Exception();
}
}
}
As we can see, we have the function ‘testRetry()’, which executes the function ‘RetrySampleMethod()’. In this function, which would simulate our real code, we have added an exception. In general, we would use a specific type of exception, but for this example, we’ll just use the base class.
Now, in testRetry, we have used Polly to execute the code 4 times (1 original + 3 retries). After accumulating the 4 errors, it will throw an Exception, which we have caught in a Try Catch block.
Fallback Pattern
To avoid this Try Catch block and do it more in the “Polly way”, we can replace it with a combination with Fallback. Therefore, the previous code is equivalent to:
using Polly;
using Polly.Timeout;
using System;
using System.Diagnostics;
namespace TestPolly
{
class Program
{
static void Main(string[] args)
{
testRetry();
}
static void testRetry()
{
Policy
.Handle<Exception>()
.Fallback(_ => Console.WriteLine("Retry exceed"))
.Wrap(
Policy
.Handle<Exception>()
.Retry(3)
)
.Execute(RetrySampleMethod);
Console.WriteLine("Finish");
Console.ReadLine();
}
static int counter = 0;
[DebuggerNonUserCode]
static void RetrySampleMethod()
{
Console.WriteLine(counter);
counter++;
throw new Exception();
}
}
}
Timeout Pattern
The Timeout pattern consists of stopping an action if the execution time is greater than a specified interval.
using Polly;
using Polly.Timeout;
using System;
using System.Diagnostics;
namespace TestLibraries
{
class Program
{
static void Main(string[] args)
{
testTimeout();
}
static void testTimeout()
{
Policy.Timeout(1, TimeoutStrategy.Pessimistic, onTimeout: (context, timespan, task) =>
{
Console.WriteLine("Timeout");
})
.ExecuteAndCapture(TimeoutSampleMethod);
Console.WriteLine("Finish");
Console.ReadLine();
}
[DebuggerNonUserCode]
static void TimeoutSampleMethod()
{
System.Threading.Thread.Sleep(2000);
}
}
}
In this case, our code is simulated by the function ‘TimeoutSampleMethod()’ which, as we can see, only has a blocking wait of 2 seconds. In the ‘testTimeout()’ function we use Polly to launch the previous function with a Timeout of 1 second. The pessimistic strategy is used for functions that do not implement CancelationToken.
Circuit-Breaker Pattern
The Circuit-Breaker pattern stops requests to a system if it detects a series of errors close in time, and disables them for an interval.
using Polly;
using Polly.Timeout;
using System;
using System.Diagnostics;
namespace TestLibraries
{
class Program
{
static void Main(string[] args)
{
testCircuitBreak();
}
private static void testCircuitBreak()
{
var pol = Policy
.Handle<Exception>()
.CircuitBreaker(
exceptionsAllowedBeforeBreaking: 10,
onBreak: (exception, timespan) => { Console.WriteLine("Break"); },
onReset: () => { Console.WriteLine("Reset"); },
durationOfBreak: TimeSpan.FromSeconds(5)
);
while(true)
{
pol.ExecuteAndCapture(CircuitBreakSampleMethod);
}
}
[DebuggerNonUserCode]
static void CircuitBreakSampleMethod()
{
System.Threading.Thread.Sleep(100);
Console.WriteLine("Error");
throw new Exception();
}
}
}
Finally, you’ll see that in all the examples we have marked the function that throws the Exception with the attribute [DebuggerNonUserCode]. This is necessary for debugging in Visual Studio, because otherwise it catches the exception we throw, even if it is managed by Polly. If it were code from an external library, this attribute would not be necessary.
That’s how easy it is to implement patterns with the Polly library. A very useful tool that should be part of your collection of favorite libraries.

