Everything you need to know about Polly
History
I heard the first time about Polly somewhere around 2016–2017, and I think it had only a preview version at that time. I really liked it, since I was searching for the equivalent of Hystrix from Java into .NET, and at that time at least, there wasn’t anything like that.
What is this parrot?
Their definition says it all: “Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, Rate-limiting and Fallback in a fluent and thread-safe manner.”, and can be found here with its NuGet package. There you can also find a lot of examples of how you can write your policies. If you are using older .NET versions, and you don’t work in .NET Core, you can also, have the benefit of using Polly, since it supports most of the older versions also; you can check the supported targets here.
Personal feedback
To be honest, I’ve used Polly only with retry and circuit breaker policies in production, and made some pet projects with the cache and fallback policies, but never got the chance or the need to add them in a production code. Don’t get me wrong, they are working fine, and easy to do, but I am not a fan of adding stuff in a production code, just because they are fancy.
What I can say is that for the retry policy, I didn’t have, ever, a business scenario in which I couldn’t use Polly. You can retry a number of times, you can wait and retry a fixed number of seconds, or an exponential time, you can retry forever; for the circuit breaker, you can a failure threshold, you have the duration of the break, the min throughput, you basically have anything you want, so really, both are highly configurable; and if you read my articles, I almost never say such big words, about packages.
Show me some code!
Let’s say you have a method that you want to retry 5 times (if it throws an exception) and you want to log its result and the exception message for each exception that may be thrown.
With Polly, the code would look more “elegant”, but to be honest, I wouldn’t add another NuGet package, if I need only a retry in one single place.
For example, if you have multiple instances of an API or you get the feeling that you might get concurrency expectations, you might want to retry your logic, without sending back an error to the client. As a real-life example, this might look like this:
Another good example may be the one with wait and retry. Do you remember all those times when a 3rd party system went down for 3–5 min, and after that everything was fine? Do you remember how much time you lost debugging the problem and after some time you realised it was just a transient problem? If you just retried, and the 3rd party system was down, due to the high CPU, memory, DB issues or even network traffic, to burst that service with retries and add to it more load won’t help it at all. This is why this “wait and retry” appeared, to give the 3rd party system time to recover.
Regarding caching, I won’t show you any code since there are a lot of examples, but those I liked most can be found on the “no dogma blog” (the blog written by Bryan Hogan), and the articles can be found here and here (on his posts you can find the code sources as well). What is worth mentioning is that you can easily add some configuration on the app's startup, and all the requests (responses for the requests) will be cached, or you can configure policies on the request level, and you may have a policy for each request. In my mind, this is a pretty cool thing.
You can have policies to do even different things based on response codes for example, or re-authorization if needed! You just need to create a delegate and that’s all!
If you want more policies nested, you can do that, but if you want to reuse them in multiple places my recommendation would be to use “IPolicyWrap”. It will make your code reusable and you’ll have less code in front of your eyes and let you focus on your business logic, not on the policies.
Testing
If you’re thinking that is pretty hard to test this, well, you’re wrong.
Option one (the ugly one) would be to mock the policy and do your unit tests. This option will make Sonar, or whatever you have over there (for checking the code coverage), happy. This will give you “the ability” to test your “business logic”, aka the logic that should be retried, easier.
For this you most likely need the next packages:
If you don’t want to have anything to do with Polly you have the option to use Policy.NoOpAsync and your policy won’t do a thing.
Option two would be to use Simmy, which is a tool for chaos engineering. With this tool, you’ll be able to inject “problems”, and you’ll be able to test not only the logic but also the policies. I highly recommend doing this also.
Conclusion
Polly is a nice open-source project that I really recommend. It can be used with any type of request (GET, PUT, etc), but it’s your job to take care they are idempotent; also, it is thread save, but as you can imagine, it’s not a silver bullet. It shouldn’t be used everywhere, and you shouldn’t add it only for only one small thing, but you should always consider it when you build something.