Chyba nikogo nie dziwi, że aplikacje czasem nie działają. Jedną z najlepszych rzeczy, jaką możemy zrobić to przygotować się na taki stan i ograniczyć straty w pozostałych częściach systemu.
Z pomocą przychodzi nam biblioteka Resilience4j, czyli lekka biblioteka udostępniająca narzędzia dla tworzenia systemów tolerujących awarię, zainspirowana przez Netflix Hystrix, ale zaprojektowana dla Javy 8 i programowania funkcjonalnego.
Główne moduły biblioteki to: CircuitBreaker, Bulkhead, RateLimiter, Retry, TimeLimiter oraz Cache. Biblioteka opiera się na dekoratorach, których możemy użyć na lambdzie, metodzie, lub interfejsie funkcyjnym.
Zobaczmy, co one oferują i jak można ich użyć.
Jak możemy tego użyć?
Każdego z modułów można użyć jako osobnej zależności, ale tu przedstawimy najszybszy i najprostszy sposób użycia Resilencje4j w połączeniu ze SpringBoot.
Aby dodać w naszej aplikacji Resilience4j, wystarczy dodać zależność na resilience4j-spring-boot2 (dodatkowo wymagane są spring-boot-starter-actuator oraz spring-boot-starter-aop).
W ten sposób w aplikacji możemy korzystać z CircuitBreaker, Bulkhead, RateLimiter, Retry oraz TimeLimiter. Funkcjonalności możemy konfigurować w konfiguracji aplikacji oraz dodawać dekoratory za pomocą adnotacji. Możliwa jest także utworzenie i konfiguracja modułów bezpośrednio w kodzie.
CircuitBreaker
W dosłownym tłumaczeniu bezpiecznik, który otwiera się, gdy wykryje, że funkcjonalność, zwykle zewnętrzna usługa, jest tymczasowo niedostępna. Pozwala to odciążyć usługę i pozwolić jej na powrót do świata żywych.
CircuitBreaker ma 3 stany:
zamknięty - normalne działanie, w trakcie którego monitorujemy działanie,
otwarty - stan po wykryciu niedostępności, przez określony czas zwracany jest błąd bez wywoływania oznaczonego kodu,
w połowie otwarty - stan występujący po otwarciu w którym sprawdzamy czy funkcjonalność zaczęła działać.
Najważniejszymi parametrami, które możemy konfigurować, są rodzaj i wielkość okna, w którym sprawdzamy procent błędów, oraz parametr określający, od jakiej ilości błędów otwieramy nasz bezpiecznik. Po skonfigurowaniu instancji CircuitBreakera możemy dodać adnotację na metodzie, która nas interesuje.
Adnotacja:
@CircuitBreaker(name="backendA",fallbackMethod="fallback")publicMono<String>method(Stringparam1){returnMono.error(newNumberFormatException());}publicMono<String>fallback(Stringparam1,IllegalArgumentExceptione){log.error("Error for backendA",e);}
Retry
Jeśli usługi, które wywołujemy, są idempotentne i nie jesteśmy pewni czy udało się wywołać daną funkcjonalność, możemy pokusić się o ponowienie takiej operacji, licząc na to, że za chwilę zacznie działać.