Oferty w Twoim regionie
Włącz powiadomienia na pulpicie
Wróć na początek

To Polly or not to Polly, czyli o funkcjonalnościach biblioteki do wykrywania błędów

O bibliotece Polly napisano już wiele. Scott Hanselman umieścił na swoim blogu świetny tekst, w którym opisał jej funkcjonalności. Na github.com można znaleźć wyczerpującą dokumentację, która zawiera wiele informacji o mechanizmach i wzorcach wykorzystywanych podczas powtarzania danej operacji, np. Circuit Breaker. W niniejszym artykule Łukasz Olbromski opowiada o swoich doświadczeniach z Polly oraz przybliża, w jaki sposób pomogła mu ona rozwiązać problem w systemie, nad którym pracował.

O Polly po raz pierwszy opowiedział mi Łukasz Pyrzyk, w czasie gdy pracowaliśmy w jednym zespole. Łukasz ma w zwyczaju przeglądać wszelkiego rodzaju nowości, w tym ciekawe projekty pojawiające się na github.com. Kiedy Łukasz trafił na Polly, biblioteka ta od razu przypadła mu do gustu. Spodobała mu się ze względu na fakt, że dostarczała bardzo ładne i czytelne (za sprawą fluent interface) API do powtarzania operacji. Mnie jednak nie od razu udzielił się entuzjazm Łukasza. Moją pierwszą reakcję na wieść o Poli można raczej streścić w zdaniu „na co mi kolejna biblioteka”.

Kilka tygodni później okazało się jednak, że Polly bardzo mi się przydała.  W systemie, nad którym pracowałem, został wykryty błąd, związany z zapisywaniem danych do bazy. Błąd powstał w wyniku przekroczenia dozwolonego czasu operacji (tzw. timeout), przez co w efekcie dane nie zostały zapisane. Dotychczas podobne sytuacje były rozwiązywane poprzez powtórzenie operacji, jednak w tej konkretnej metodzie, logika ta nie została zaimplementowana. Na pierwszy rzut okna rozwiązanie zdawało się być oczywiste: trzeba operację powtórzyć. Niestety, w tym przypadku rozwiązanie problemu okazało się być jednak nieco trudniejsze. Wynikało to z następujących przeszkód:

  • nie było wydzielonego i spójnego komponentu do powtarzania operacji;
  • każde wystąpienie powtarzania operacji było napisane inaczej, co znacznie utrudniało wprowadzenie zmian;
  • brakowało testów jednostkowych, które mogłyby zweryfikować, czy kod nadal działa poprawnie;
  • brakowało odpowiednich abstrakcji, przez co testowanie powtarzających operację metod było utrudnione;
  • nie było spójnego mechanizmu obsługi wyjątków;
  • istniały różne warunki, definiujące kiedy i ile razy należy daną operację powtórzyć.

Mając na uwadze powyższe, ze swojej strony zaproponowałem więc, aby w celu usprawnienia, całą logikę do powtarzania operacji zastąpić Polly. Nasz kod w systemie wyglądał mniej więcej tak jak poniżej.

[Kod NoPollyRetry.cs]

Dlaczego wykorzystałem Polly?

Aby rozwiązać problem, miałem trzy możliwości:

  1. załatać dziurę i po prostu napisać kod, który powtórzy wywołanie;
  2. wyodrębnić logikę powtarzania operacji do oddzielnego komponentu i zamienić pozostałe wystąpienie nowym komponentem;
  3. zastosować Polly tam, gdzie powtarzamy operację.

Zdecydowałem się na opcję nr 3. Pierwsze rozwiązanie miało wiele wad, takich jak brak spójności w obsłudze powtarzania operacji, niska testowalność kodu oraz konieczność powtarzania tego samego kodu w wielu miejscach. Ponadto znalazłem kilka innych miejsc, w których ten kod również występował.

Opcja nr 2, podobnie jak trzecia, była dobra, ale odrzuciłem ją, ponieważ nie widziałem sensu pisania takiego samego kodu, jaki oferuje Polly;  szanse, że zrobiłbym to lepiej, były bardzo małe, poza tym zabrałoby mi to sporo czasu.

Rozwiązanie nr 3 było więc najsensowniejszym wyborem. Dzięki zastosowaniu Polly nie tylko rozwiązałem problem, ale również usunąłem zbędny kod systemu, zwiększyłem jego czytelność oraz dodałem potrzebne testy. Kod wygląda teraz mniej więcej tak:

[Kod PollyRetry.cs]

Kiedy warto korzystać z Polly?

Polly warto stosować w sytuacji, kiedy chcemy daną operację powtórzyć lub gdy zależy nam na zapewnieniu czytelnej obsługi wątków, a równocześnie nie chcemy pisać długich bloków try-catch-finally, które później opakowywane są pętlą odpowiadającą za powtórzenie operacji. Ponadto Polly przyda nam się również, gdy chcemy osiągnąć spójne API, za sprawą którego nasz kod będzie czytelny i pozwoli nam, bez wnikania w szczegóły, łatwo zrozumieć całą logikę działania.

W tym miejscu warto też dodać, że Polly pomaga zaoszczędzić czas, ponieważ dzięki niej nie musimy pisać i testować powtarzającej operację logiki, a zyskaną chwilę możemy przeznaczyć na rozwiązanie palącego problemu. Nie bez znaczenia jest tu fakt, że API Polly działa w środowisku wielowątkowym.

W jakich sytuacjach Polly może być przydatna?

Moim zdaniem, mechanizm powtarzania operacji Polly warto zastosować, gdy:

  • Korzystamy z niestabilnego API, np. IWebBrowser2 w Internet Explorer.
  • Tworzymy kosztowne zasoby, których limit może być chwilowo wyczerpany (jak na przykład połączenie do bazy).
  • Istnieje ryzyko, że operacja nie zakończy się w zakładanym czasie i wyskoczy nam tzw. timeout. Taka sytuacja może mieć miejsce w przypadku, gdy czytane są dane z sieci, połączenie nie jest zbyt silne lub gdy baza danych jest chwilowo przeciążona.

Rozwiązaniem pierwszego typu problemu może być zaniechanie korzystania z wadliwego API. Kiedy jednak nie możemy sobie na to pozwolić, przede wszystkim powinniśmy przeanalizować, z jakiego powodu mamy braki w zasobach. Być może bowiem przyczyną jest zbyt mała pula połączeń lub też fakt, że zasoby nie są zwalniane. Takie błędy możemy łatwo naprawić w kodzie.

W przypadku drugiej kategorii błędów rozwiązaniem może być optymalizacja lub podłączenie dodatkowego sprzętu. Koszty takiej operacji często są jednak wysokie, dlatego niekiedy bardziej opłacalną opcją będzie przeprowadzenie operacji od początku. Zwiększenie timeoutu również może być rozwiązaniem, ale nie zawsze chcemy, aby chwilowy stan wpływał na całą konfigurację systemu.

Jeśli jednak w naszym systemie sporadycznie występują tzw. peaki i potrzebujemy większej ilości połączeń niż  zwykle, warto skorzystać z Polly lub CircuitBreaker, które z pewnością będą pomocne.

Zalety stosowania Polly

Moim zdaniem, do zalet Polly warto przede wszystkim zaliczyć:   

  • czytelny i łatwy do zrozumienia kod. Zachęcam do przejrzenia przykładów, które Scott Hanselman umieścił w swoim artykule;
  • elastyczność i wielość opcji konfiguracji:
    • liczba powtórzeń danej operacji,
    • przerwa pomiędzy powtórzeniami,
    • filtrowanie po typie wyjątku;
  • thread safety – pisanie kodu, działającego poprawnie w środowisku wielowątkowym, nie należy do zadań prostych, dlatego nawet w przypadku małej części systemu, lepiej rozwiązać problem zawczasu;
  • wysoka jakość kodu – to rzecz względna, ale dla mnie czytelne i łatwe do zrozumienia API to podstawa. Ponadto Polly ma solidny zestaw testów jednostkowych, które same w sobie również są źródłem wiedzy na temat tej biblioteki;
  • bardzo dobra dokumentacja – wyczerpująca dokumentacja potrafi zaoszczędzić czas potrzebny na zapoznanie się z działaniem biblioteki, a ta dołączona do Poli, jest nie tylko dobrze przygotowana, ale również zawiera wiele przykładów zastosowania biblioteki w praktyce;
  • Polly to projekt Open Source dostępny na github.com, dzięki czemu zawsze można sprawdzić aktualne błędy, kod, czy nawet zgłosić pull request.

Wszystkie te opcje w znaczący sposób ułatwiają zmianę działania kodu, bez konieczności wprowadzania w nim dużych zmian.

Słowo podsumowania

W moim przypadku Polly pomogło mi rozwiązać istotny problem i jednocześnie umożliwiło mi usunięcie kodu. W kolejnych miesiącach zastosowałem Polly ponownie  –  biblioteka ta przydała mi się przy okazji pracy nad kolejnymi systemami –  i tym samym stała się jednym z moich standardów.

Mam nadzieję, że niniejszym artykułem udało mi się zachęcić Czytelników do zapoznania się z biblioteką Polly. Wszystkich, którzy zdecydują się przetestować Polly w praktyce, zachęcam zaś do podzielenia się swoją opinią.

Komentarze

Napisz do nas

Przeglądając stronę wyrażasz zgodę na przetwarzanie swoich danych osobowych pozostawianych w czasie korzystania przez Ciebie z Serwisu oraz innych parametrów zapisywanych w plikach cookies przechowywanych na urządzeniu, z którego korzystasz w celach marketingowych, w tym na profilowanie i w celach analitycznych przez "IT KONTRAKT" spółka z ograniczoną odpowiedzialnością z siedzibą we Wrocławiu, ul. Gwiaździsta 66, 53-413 Wrocław i Zaufanych Partnerów IT KONTRAKT Sp. z o.o.