Scenariusz edukacyjny inspirowany praktyką. Zamówienie zostało zapisane, ale informacyjny e-mail nie wyszedł. To nie jest jedna nieudana operacja. To jeden zakończony wynik biznesowy i jeden niespełniony skutek pomocniczy.

Najpierw nazwij wynik

Jeżeli przyjęcie zamówienia kończy się zatwierdzeniem rekordu, ten moment jest granicą wyniku biznesowego. E-mail, SMS, indeks wyszukiwarki czy wpis analityczny mogą być skutkami tego wyniku. Nie wolno pozwolić, by awaria dodatku zmieniła prawdziwe „zamówienie przyjęte” w fałszywe „spróbuj ponownie”. Tak właśnie rodzą się duplikaty.

Asynchroniczność nie oznacza jednak „wyślij coś na kolejkę i miej nadzieję”. Zapis zamówienia oraz publikacja komunikatu to dwa zapisy. Jeżeli proces umrze pomiędzy nimi, zamówienie istnieje, a wiadomości nie ma.

Trwały zamiar wykonania

Najprostszy wariant to rekord oczekującego powiadomienia zapisany w tej samej lokalnej transakcji co zamówienie. Proces roboczy odczytuje rekord, wysyła wiadomość i oznacza wynik. Gdy więcej odbiorców korzysta ze zdarzeń, tę samą zasadę realizuje transactional outbox: zmiana domenowa i wpis do skrzynki wychodzącej powstają atomowo, a osobny relay publikuje wpis dalej.

Outbox zamyka lukę między bazą i brokerem, ale nie czyni systemu magicznie „exactly once”. Relay może opublikować tę samą wiadomość ponownie. Konsument potrzebuje stabilnego identyfikatora operacji oraz idempotencji albo deduplikacji. Dla e-maila warto również ustalić, czy drugi identyczny komunikat jest tolerowany, czy ma być powstrzymany.

Retry jest decyzją, nie odruchem

  • ponawiaj tylko zadanie, które się nie udało, a nie całą operację biznesową;
  • stosuj ograniczoną liczbę prób, opóźnienie i jitter, aby nie dobić zależności podczas awarii;
  • po wyczerpaniu prób zachowaj zadanie do obsługi i uzgodnienia zamiast usuwać ślad;
  • mierz wiek najstarszego oczekującego zadania, liczbę prób i odsetek trwałych błędów;
  • pokaż użytkownikowi prawdę: zamówienie przyjęto, a potwierdzenie może przyjść później.

Jak sprawdzić decyzję

Testuj trzy awarie: poczta jest niedostępna, proces kończy się po commicie bazy, a relay publikuje komunikat dwukrotnie. Wynik ma być nudny: jedno zamówienie, trwałe zadanie, kontrolowane ponowienie i co najwyżej jedno widoczne powiadomienie. Architektura odporna bywa nudna. To komplement.

Granica zastosowania: jeśli powiadomienie jest prawnym lub biznesowym warunkiem przyjęcia operacji, nie jest skutkiem pomocniczym. Najpierw trzeba ustalić kontrakt, dopiero potem dobierać wzorzec.

Dalsza lektura: AWS Prescriptive Guidance: Transactional outbox pattern. Dokumentacja opisuje atomowy zapis zdarzenia i potrzebę idempotentnego konsumenta.