Spring Kafka z obsługą Retry-After

Biblioteka Spring Kafka umożliwia obsługę błędów przez sprawdzony mechanizm exponential back-off. Jednak jeśli błędem jest HTTP 429 „Too Many Requests” (czyli rate limiting), zwykłe wykładnicze zwiększanie przerw między kolejnymi próbami jest trochę jak atak brute force: marnujemy zasoby na próbowanie przed czasem, albo marnujemy czas czekając za długo. Lepiej byłoby czekać dokładnie tyle, ile wysyła serwer.

W dalszej części pokażę, jak podejść do implementacji. W dużym skrócie, wystarczy napisanie jednej nieskomplikowanej klasy.

Czytaj dalej „Spring Kafka z obsługą Retry-After”

Wyciszanie śmiecących logów Springa przy kończeniu testów

Wielowątkowe testy (takie jak używające Kafki) są źródłem kłopotów. Na przykład zaśmiecają przebieg buildu w Gradle’u.

Normalnie Gradle przechwytuje stdout i stderr z testów, przerzuca je do raportów HTML-owych, a terminal zachowuje czysty:

> Task :my-module:testClasses
> Task :my-module:test

Moduły korzystające ze Springa i uruchamiające wiele wątków potrafią kompletnie zabić czytelność terminala:

> Task :my-module:testClasses
INFO [ntainer#0-0-C-1] o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-my.event-2, groupId=my.event] Revoke previously assigned partitions my.event-0, my.event-1, my.event-2
20
ERROR [sson-netty-1-15] i.n.u.c.D.rejectedExecution             : Failed to submit a listener notification task. Event loop shut down?
java.util.concurrent.RejectedExecutionException: event executor terminated
	at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:934)
> Task :my-module:test

Łatwo może się zdarzyć, że dostaniemy ponad 100 niechcianych śmieciowych linii.

W dalszej części artykułu objaśnię, co w działaniu biblioteki spring-test powoduje taki zgrzyt w integracji z Gradle’em. Zaproponuję też obejście problemu za pomocą specjalnego beana wyłączającego część logowania.

Czytaj dalej „Wyciszanie śmiecących logów Springa przy kończeniu testów”

Pułapki transakcji Springa dla programistów Kotlina

Wydaje się, że Spring i Kotlin to dobre połączenie. Z jednej strony najbardziej popularny framework dla Javy, ale deklarujący wsparcie dla języka od JetBrains. Z drugiej Kotlin został zaprojektowany dla jak największej kompatybilności z Javą. Na papierze i w ogłoszeniach na social mediach wszystko gra. Tyle że w rzeczywistości można bardzo nieprzyjemnie się zaskoczyć, niestety zazwyczaj dopiero na produkcji.

Problem będący głownym bohaterem tego artykułu leży w różnym podejściu do wyjątków w obu światach.

Pisząc w Kotlinie można zapomnieć o dyskusjach programistów Javy, czy wyjątek ma być checked czy nie. Jeśli w repozytorium piszemy wyłącznie w jednym języku, wszystko nam jedno i nie trzeba sobie tym zawracać głowy. Chyba że kod działa w Springu. Wtedy brak uwagi kończy się zobaczeniem UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only. Zgodnie ze słowami 'unexpected’ i 'silent’, jest to sytuacja zaskakująca, a do tego upierdliwa w zdiagnozowaniu.

Czytaj dalej „Pułapki transakcji Springa dla programistów Kotlina”

Fast and stable MongoDB-based tests in Spring

Tradycyjne uruchamianie testowego MongoDB przez Flapdoodle Embedded Mongo kontra nowoczesne podejście z Testcontainers. Krótko o kontekstach w testach Springa przy okazji potwornego zużycia zasobów przez Flapdoodle. Mierzenie obciążenia systemu narzędziem sar i o użyteczności starego dobrego gnuplota. Artykuł po angielsku — zapraszam na Medium*.

* wejście z tego specjalnego linku nie zmniejszy waszego miesięcznego limitu darmowych artykułów w serwisie

3 najbardziej pouczające materiały z 2019

Styczeń to na różnych stronach i blogach okres publikowania podsumowań minionego roku. Miałem zamiar napisać artykuł w stylu „3 najlepsze książki programistyczne, jakie przeczytałem w 2019”, ale okazało się, że nie zbiorę trzech: musiałbym albo zaproponować rzeczy, z których nie byłem w pełni zadowolony, albo książki niezwiązane ściśle z branżą IT. Zamiast tego mogę zaproponować 3 rzeczy związane z programowaniem, ale niekoniecznie wydrukowane na papierze: jedną książkę, jedną publikację w sieci i jedno nagranie wideo.

Czytaj dalej „3 najbardziej pouczające materiały z 2019”

Niebezpieczny isEmpty() z utili Springa

Wyobraźmy sobie, że znajdujemy w projekcie taki kod w Javie (lub prawie identyczny — w Kotlinie):

public void assertNoViolations(Collection<ConstraintViolation> violations) {
    if (!isEmpty(violations)) {
        throw new IllegalStateException("violates constraints: " + violations);
    }
}

Na oko — kod jak kod, robi co trzeba, nuda. Co może pójść nie tak?

Metoda zgodnie z oczekiwaniami bezproblemowo akceptuje nulla. Rzuca wyjątkiem, gdy przekażemy jej listę zawierającą contraint violations. Jest jeden szkopuł:

assertNoViolations(emptyList());
java.lang.IllegalStateException: violates constraints: []

Jak to jest możliwe?

Czytaj dalej „Niebezpieczny isEmpty() z utili Springa”
Creative Commons License
Except where otherwise noted, the content by Piotr Kubowicz is licensed under a Creative Commons Attribution 4.0 International License.