Gdzieś w każdej umowie integracyjnej znajduje się zdanie w rodzaju „każde zamówienie zostanie przesłane dokładnie raz”. Nigdy, ani razu, nie było to prawdą. Sieć uległa partycji w trakcie żądania i nadawca ponowił próbę; kolejka dostarczyła ponownie po awarii konsumenta; operator magazynu nacisnął przycisk eksportu dwa razy. Duplikaty to nie tryb awarii - to pogoda.
Klucze idempotencji, dobierane starannie
Rozwiązanie jest stare i mało efektowne: każdy komunikat niesie klucz, a przetwarzanie nie ma żadnego efektu, gdy klucz już wystąpił. Wszystkie ciekawe decyzje dotyczą wyboru tego klucza.
- Klucze naturalne biją klucze generowane. Synchronizacja zamówień oparta na kluczu
order_id + statusprzetrwa regenerację outboxa przez nadawcę; losowy UUID wygenerowany w momencie wysyłki - nie. - Zakres klucza powinien obejmować efekt, nie komunikat. Jeśli jeden komunikat tworzy fakturę i rezerwuje zapas, to są dwa efekty z dwoma kluczami - w przeciwnym razie częściowa awaria uniemożliwi wam bezpieczne ponowienie żadnego z nich.
- Wygaszajcie klucze świadomie. Magazyn deduplikacji, który rośnie w nieskończoność, to bomba zegarowa; taki, który wygasa zbyt szybko, ponownie wprowadza duplikaty. Domyślnie stosujemy 3× maksymalny horyzont ponowień nadawcy.
Test, który ma znaczenie
Każda integracja, którą wdrażamy, przechodzi to, co wewnętrznie nazywamy testem podwójnego stuknięcia: odtwarzamy cały wczorajszy dziennik komunikatów na dzisiejszym systemie, dwukrotnie, i porównujemy wynikowy stan. Jeśli po drugim przebiegu cokolwiek się zmieniło, potok nie jest gotowy.
To brutalny test i podczas developmentu zawodzi bez przerwy - na znacznikach czasu, na polach audytowych „utworzone przez”, na licznikach sekwencji. Każde niepowodzenie to miejsce, w którym ponowne dostarczenie o 3 w nocy po cichu uszkodziłoby dane. O wiele taniej jest wychwycić to podczas developmentu niż na produkcji.