17 : Who's a pretty boy then?

13 May 2022

Polly - do you need it? Should you be using it? When can you use it? How do you use it? We'll be answering all these questions and discovering (nearly) all there is to know about Polly in this episode.

Random fact

There are around 393 species of Parrots

There are lots of different types of parrots out there, most of them are found in tropical and subtropical surroundings.

There are 3 different families of parrots: the Psittacoidea, which are known as true parrots. Cacatuoidea, which are cockatoos and Strigopoidea, which are New Zealand parrots.

Rowan: Don’t forget my favourite parrot - the Flamin Galah! 😆

Introduction

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fall-back in a fluent and thread-safe manner.

So what does that mean to me?!

What does it do

Reduce the number of exceptions or errors shown to users

Handles transient error conditions

An error that only lasts a few seconds - network issues

Makes software more resilient by handling faults - typically when interacting with external resources like dbs, hard disks, http calls, 3rd party services etc

Does this by introducing an abstraction that executes a given operation delegate, whether it be synchronous or Asynchronous, using one or more Policies.

Resilience policies

Polly offers multiple resilience policies:

  • You are not limited to just one policy. Polly support policy registries, via named policies, that allow you to configure multiple policies that can be used in combination with each other throughout your app if needed.

When would you think about using something like Polly

Anytime you’re calling something outside of your control?

Why not just use a try/catch and a while loop to keep retrying?

  • you’d have to write that yourself
  • the simple version would be front and centre of you codebase, tightly coupled flow
    • might be harder to test
    • might be harder to change
  • If you wanted to progress to something a bit more sophisticated like one of the strategies already mentioned (upgrade to bulkhead / circuit breaker / backoff), that would require changing code, getting it right, retesting, potentially introducing other problems in the process. The Polly abstraction gets out of the way of your logic, nice and decoupled
  • You’d have to write tests around your retry logic
  • Why would you build this type of thing yourself?!

How do you use it?

Install package from NuGet

Think about the type of policy / policies that you need to apply

Write some code to write up your calls to external services or 3rd party libraries.

Policy.Handle<WebException>()
  .RetryForever()
  .Execute( () ⇒ {  your code here  } );

The .Net Core Http Client even integrates with it, to allow you to configure the client to use specific Polly policies

How to configure a http client to use exponential backoff calls with Polly:

  1. Use package Microsoft.Extensions.Http.Polly
  2. Use the AddPolicyHandler extension method when configuring the HttpClient in Startup.cs
  3. Point to your specific retry policy
//1. reference the extension package Microsoft.Extensions.Http.Polly

//ConfigureServices()  - Startup.cs
services.AddHttpClient<IBasketService, BasketService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
.AddPolicyHandler(GetRetryPolicy());

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
                                                                    retryAttempt)));
}

You can even add a jitter strategy to the retry policy:

  • A regular Retry policy can affect your system in cases of high concurrency and scalability and under high contention.
  • To overcome peaks of similar retries coming from many clients in partial outages, a good workaround is to add a jitter strategy to the retry algorithm/policy
  • This will apply smooth and evenly distributed retry intervals applied with a well-controlled median initial retry delay on an exponential backoff.
  • This approach helps to spread out the spikes when the issue arises
var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);

var retryPolicy = Policy
.Handle<FooException>()
.WaitAndRetryAsync(delay);

Wrap up

A mature framework even used by Microsoft - well worth using in pretty much any project!

Polly targets .NET Standard 1.1 (coverage: .NET Core 1.0, Mono, Xamarin, UWP, WP8.1+) and .NET Standard 2.0+ (coverage: .NET Core 2.0+, .NET Core 3.0, and later Mono, Xamarin and UWP targets). The NuGet package also includes direct targets for .NET Framework 4.6.1 and 4.7.2.

https://github.com/App-vNext/Polly

Loads of examples on the GitHub site to get you started

OS project/utility of the week

Spectre.Console

https://github.com/spectreconsole/spectre.console

Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications.

Spectre.Console.AnsiConsole Features

  • Easily output text with different colours and even styles such as bold, italic and blinking with a Rich inspired markup language.
  • Supports 3/4/8/24bit colours in the terminal with auto-detection of the current terminal's capabilities.
  • Render complex widgets such as tablestrees, and even ASCII images.
  • Display progress for long running tasks with live displays of progress and status controls.
  • Prompt user input with strongly typed text input or via single-item select and multiple item select controls.
  • Format .NET exceptions with custom colour coded themes and styles.
  • Written with unit testing in mind.