Minden integrációs szerződésben van valahol egy olyan mondat, hogy „minden megrendelés pontosan egyszer kerül átvitelre”. Ez még soha nem volt igaz. A hálózat kérés közben szétvált, és a küldő újrapróbálkozott; a sor újraküldött egy fogyasztói összeomlás után; egy raktári operátor kétszer nyomta meg az exportgombot. A duplikátumok nem hibamód - ezek időjárás.
Idempotenciakulcsok, gondosan megválasztva
A megoldás régi és nem túl látványos: minden üzenet hordoz egy kulcsot, és a feldolgozás nem történik meg (no-op), ha a kulcsot már láttuk. Az érdekes döntések mind a kulcs kiválasztásában rejlenek.
- A természetes kulcsok jobbak a generáltaknál. Egy
order_id + statusalapján kulcsolt megrendelés-szinkronizálás túléli, ha a küldő újragenerálja a kimenő postaládáját; egy küldéskor generált véletlen UUID nem. - A kulcsot a hatáshoz rendelje, ne az üzenethez. Ha egy üzenet számlát hoz létre és készletet könyvel, ez két hatás, két kulccsal - különben egy részleges hiba esetén egyiket sem tudja biztonságosan újrapróbálni.
- Tudatosan járjon le a kulcsoknak. Egy örökké növekvő deduplikációs tár időzített bomba; ha túl hamar jár le, az visszahozza a duplikátumokat. Alapértelmezésként a küldő maximális újrapróbálkozási horizontjának 3×-osát használjuk.
A teszt, ami számít
Minden általunk szállított integráció átmegy azon, amit belsőleg double-tap tesztnek nevezünk: a tegnapi teljes üzenetnaplót kétszer visszajátsszuk a mai rendszeren, és összehasonlítjuk a kapott állapotot. Ha a második lefutás során bármi megváltozott, az adatfolyamat még nincs kész.
Ez egy kíméletlen teszt, és a fejlesztés során folyamatosan elbukik - időbélyegeken, „létrehozta” audit mezőkön, sorszámlálókon. Minden bukás egy olyan pont, ahol egy hajnali 3 órás újraküldés csendben megrongálta volna az adatokat. Sokkal olcsóbb ezt a fejlesztés során elkapni, mint az éles üzemben.