Many words have been written about the Polly library. Scott Hanselman published on his blog a great article, where he described its functionalities. On github.com, you can find comprehensive documentation, which includes a lot of information about the mechanisms and models used while repeating a given operation, e.g. Circuit Breaker. In this article, Łukasz Olbromski discusses his experiences with Polly and provides an outline of how it helped him solve a problem in a system on which he was working.
The first time I heard of Polly was from Łukasz Pyrzyk when we were working together in one team. Łukasz has a habit of following all the news, including interesting projects which appear on github.com. When he came across Polly, the library immediately appealed to him. He liked it due to the fact that it offered a very nice-looking and clear (because of its fluent interface) API for repeating operations. Having said that, it wasn’t at the very beginning that I got infected with Łukasz’s enthusiasm. I could sum up my reaction to the news about Polly with the words “why should I need another library?”
A few weeks later, however, it turned out that Polly had become very useful to me. An error was detected in a system I was working on – one related to writing data into the database. The error occurred as a result of exceeding the permitted operation time (so-called timeout), which caused the data not to be written. Previously, such situations were rectified by repeating the operation, but this logic hadn’t been implemented in that specific method. At first glance, the solution seemed to be obvious – the operation must be repeated. Unfortunately, in that case, the solution to the problem turned out to be a little more difficult. It stemmed from the following hindrances:
- there was no isolated and coherent component for repeating operations;
- every instance of repetition was written in a different way, which considerably hampered the introduction of changes;
- there were no unit tests that could verify whether the code was still working properly;
- there were no appropriate abstractions, due to which testing the methods repeating the operation was more difficult;
- there was no coherent mechanism for handling exceptions;
- there were different conditions defining when and how many times a given operation was to be repeated.
Bearing in mind the above, I suggested, on my part, that the whole logic for repeating operations be replaced with Polly to streamline the process. Our code in the system looked more or less like what you see below.
Why did I use Polly?
I had three options to solve the problem:
- patch the hole and just write a code that would repeat the call;
- isolate the logic of repeating the operation into a separate component and replace the remaining instance with the new component;
- use Polly where the operation is repeated.
I decided I’d go for option 3. The first solution had many drawbacks, such as the inconsistency in handling the repetition of the operation, low code testability, and a need for repeating the same code in many places. What’s more, I found a few other places where the code was also present.
Option 2, as was the case with the third one, was good, but I ruled it out, as I didn’t see the point in writing the same code as that offered by Polly; there was little change I’d do it better, and it would have taken a long time.
Solution 3 was, therefore, the most reasonable choice. Thanks to using Polly, not only did I solve the problem but I also removed the redundant system code, as well as improving its clarity, and adding the necessary tests. Now the code looks more or less like this:
When is it a good idea to use Polly?
It’s a good idea to use Polly when you want to repeat a certain operation or when it’s important to you that clear handling of threads is ensured while avoiding a need to write long try-catch-finally blocks, which are later wrapped with a loop responsible for repeating the operation. Moreover, Polly will come in handy if you want to attain a consistent API, due to which your code will be clear, allowing you, without delving into detail, to easily understand the whole functional logic.
It’s worth adding here that Polly helps you save time, as thanks to it, you don’t have to write and test the logic repeating the operation, but instead, you can spend the moment you regained to solve an urgent problem. Also of importance is the fact that Polly’s API works in a multithread environment.
In what situations can Polly be useful?
I believe that it’s a good idea to apply Polly’s mechanism for repeating operations if:
- You use an unstable API, e.g. IWebBrowser2 in Internet Explorer.
- You create costly resources whose limit may be temporarily exhausted (e.g. connecting to the base).
- There’s a risk that the operation won’t finish in the assumed time and you’ll get a so-called timeout. A situation like this may occur in a case where data from the web is being read, the connection isn’t too strong, or the database is temporarily overloaded.
Giving up the use of the faulty API may be a solution to the first type of problem. However, if you can’t afford it, you should, first of all, analyse what causes the resource shortages. Perhaps the root of the problem is a too small connection pool or the fact that resources aren’t released. Such errors can be easily repaired in the code.
As far as the second category of errors goes, the solution could be to optimise or connect extra hardware. The cost of such an operation, however, can be high, so sometimes it pays off more to carry out the operation from scratch. To increase the timeout may also be a solution, but you don’t always want a temporary state impact the whole system configuration.
But if your system occasionally experiences so-called peaks and you need a bigger number of connections than usually, it’s a good idea to use Polly or CircuitBreaker, which are certain to be useful.
Advantages of using Polly
In my opinion, the following should be considered as Polly’s advantages:
- Code that’s clear and easy to understand. I recommend taking a look at the examples included by Scott Hanselman in his article;
- flexibility and multiple configuration options:
- number of repetitions of an operation,
- pause between repetitions,
- filtering according to exception type;
- thread safety – writing code that works properly in a multithread environment is no easy feat, so even if it’s about a small part of the system, it’s better to solve the problem in advance;
- high quality of the code – it’s a relative matter, but in my book, API that’s clear and easy to understand is essential. Moreover, Polly has a robust set of unit tests, which in themselves are also a source of knowledge about this library;
- very good documentation – in-depth documentation can save the time to familiarise oneself with how the library works, and the one that comes with Polly is not only well prepared but it also includes many examples of the library’s application in practice;
- Polly is an Open Source project available on github.com, thanks to which you can always check current errors, code, or even create a pull request.
All these options considerably facilitate changing the way the code works without a need for introducing big changes in it.
A few words of summary
In my case, Polly helped me solve a significant problem while making it possible to remove the code. Over the months that followed, I applied Polly again – the library proved useful when I was working on new systems – thus becoming one of my standard tools.
I hope that with this article I succeed in encouraging the Readers to become acquainted with Polly. All of you who decide to test it in practice are welcome to share their opinions.