Přesně-jednou je lež: navrhování integrací pro duplicity

Tři kopie stejné dlaždice zprávy sbíhající se do jedné zpracované dlaždice

V každé integrační smlouvě je někde věta jako „každá objednávka bude přenesena přesně jednou." Nebyla pravdivá ani jednou. Síť se uprostřed požadavku rozdělila a odesílatel to zkusil znovu; fronta doručila zprávu znovu po pádu konzumenta; skladník dvakrát stiskl tlačítko exportu. Duplicity nejsou porucha - jsou počasí.

Idempotentní klíče, volené s rozvahou

Řešení je staré a nevzhledné: každá zpráva nese klíč a zpracování je no-op, pokud už byl klíč jednou viděn. Všechna zajímavá rozhodnutí spočívají ve volbě klíče.

  • Přirozené klíče poráží generované. Synchronizace objednávek s klíčem order_id + status přežije, když si odesílatel znovu vygeneruje svůj outbox; náhodné UUID vytvořené v okamžiku odeslání ne.
  • Rozsah klíče vázejte na efekt, ne na zprávu. Pokud jedna zpráva vytvoří fakturu a zaúčtuje sklad, jde o dva efekty se dvěma klíči - jinak vás částečné selhání připraví o možnost bezpečně zopakovat ani jeden z nich.
  • Nechte klíče záměrně expirovat. Úložiště pro deduplikaci, které roste donekonečna, je časovaná bomba; takové, které expiruje příliš brzy, znovu vpustí duplicity. Standardně nastavujeme 3× maximální horizont opakování odesílatele.

Test, na kterém záleží

Každá integrace, kterou dodáme, projde tím, čemu interně říkáme test dvojitého klepnutí: přehrajeme celý včerejší log zpráv proti dnešnímu systému, dvakrát, a porovnáme výsledný stav. Pokud se při druhém průchodu cokoliv změnilo, pipeline není hotová.

Je to brutální test a během vývoje neustále selhává - na časových razítkách, na auditních polích „vytvořil", na sekvenčních čítačích. Každé selhání je místo, kde by doručení zprávy ve tři ráno tiše poškodilo data. Mnohem levnější je zachytit to při vývoji než v produkci.