Et sted i hver eneste integrasjonskontrakt står det en setning som «hver ordre vil bli overført nøyaktig én gang». Den har aldri vært sann. Nettverket ble partisjonert midt i forespørselen og avsenderen gjorde et nytt forsøk; køen leverte på nytt etter at en konsument krasjet; en lageroperatør trykket på eksportknappen to ganger. Duplikater er ikke en feiltilstand - de er vær.
Idempotensnøkler, valgt med omhu
Løsningen er gammel og lite glamorøs: hver melding bærer en nøkkel, og behandlingen er en no-op når nøkkelen allerede er sett. De interessante beslutningene ligger alle i valget av nøkkel.
- Naturlige nøkler slår genererte. En ordresynkronisering nøkkelbasert på
order_id + statusoverlever at avsenderen regenererer utboksen sin; en tilfeldig UUID generert ved sendetidspunktet gjør det ikke. - Avgrens nøkkelen til effekten, ikke meldingen. Hvis én melding oppretter en faktura og reserverer lagerbeholdning, er det to effekter med to nøkler - ellers vil en delvis feil gjøre det utrygt å prøve på nytt for noen av dem.
- La nøkler utløpe med omhu. En dedup-lagringsenhet som vokser for alltid, er en tikkende bombe; en som utløper for tidlig, gjeninnfører duplikater. Vi bruker som standard 3× avsenderens maksimale tidshorisont for nye forsøk.
Testen som betyr noe
Hver eneste integrasjon vi leverer, består det vi internt kaller dobbelttrykk-testen: spill av hele gårsdagens meldingslogg mot dagens system, to ganger, og sammenlign den resulterende tilstanden. Hvis noe endret seg på den andre kjøringen, er pipelinen ikke ferdig.
Det er en brutal test, og den feiler stadig under utvikling - på tidsstempler, på «opprettet av»-revisjonsfelt, på sekvenstellere. Hver feil er et sted der en levering på nytt klokken tre om natten stille og rolig ville ha korrumpert data. Langt billigere å fange det under utviklingen enn i produksjon.