Preskočiť na obsah
Zapolu

17. júna 2026, Luboš Zápotočný

Webhooky sa opakujú. Vaša integrácia s tým musí rátať.

Platobné a platformové webhooky sa v okne na opakovanie doručujú aspoň raz, nie presne raz. Čo dvojité doručenie pokazí a ako ho idempotentné handlery absorbujú.

Prečítajte si dokumentáciu webhookov ktoréhokoľvek seriózneho poskytovateľa (Stripe, Shopify, Adyen, GoPay) a nájdete v tej či onej podobe to isté varovanie: doručenia môžu nastať viac než raz. V rámci okna na opakovanie je kontrakt at-least-once, nie exactly-once; ak váš endpoint zostane celé okno nedostupný, udalosť nepríde ani raz, a preto je pod všetkým ostatným záchytnou poistkou rekonciliačná úloha, ktorá si stav doťahuje z API poskytovateľa. Exactly-once doručenie cez nespoľahlivú sieť sa zaručiť nedá, takže poskytovatelia robia rozumnú vec: keď si nie sú istí, či ste udalosť dostali, pošlú ju znova.

Väčšina integrácií je napísaná, akoby tá klauzula neexistovala. Fungujú v deme, fungujú prvý mesiac, a potom niekde medzi poskytovateľom a odpoveďou 200 nastane timeout a tá istá udalosť order.paid príde dvakrát.

Čo dvojité doručenie naozaj pokazí

  • Zákazník dostane dve potvrdenia objednávky.
  • Zásoby sa odpočítajú dvakrát a vzniká fantómové „vypredané“.
  • Faktúra sa vystaví dvakrát a nezrovnalosť sa objaví pri účtovnej uzávierke.
  • Vernostný kredit sa pripíše dvakrát a čísla prestanú sedieť.

Nič z toho pritom nie je chyba poskytovateľa; ten urobil presne to, čo má v dokumentácii. Chyba je v handleri, ktorý sa spoliehal na sľub, ktorý nikto nedal.

Riešením je idempotencia

Idempotentný handler vyprodukuje rovnaký koncový stav bez ohľadu na to, či udalosť spracuje raz alebo päťkrát. Táto jediná vlastnosť absorbuje opakovania, manuálne replaye a celú triedu race conditions. Dosiahnuť ju je predovšetkým otázka disciplíny:

  1. Každej udalosti kľúč. Poskytovatelia posielajú ID udalosti; ak ho ten váš neposiela, odvoďte si ho zo stabilných polí. Spracované ID si zaznamenajte a duplikáty preskočte. Vynucujte to unique constraintom v databáze: kontrola „už som to videl?“ v aplikačnom kóde má race window, constraint nemá.
  2. Uprednostnite absolútny stav pred relatívnymi zmenami. „Nastav status na zaplatené“ je prirodzene idempotentné. „Odpočítaj zo zásob 2“ nie je. Keď poskytovateľ posiela delty, prekladajte ich na upserty proti vlastnému záznamu udalosti, nie na slepú aritmetiku.
  3. Rátajte aj s prehodeným poradím. Opakovania prichádzajú aj mimo poradia; order.updated môže doraziť pred order.created. Verzie alebo časové pečiatky na cieľovom zázname („aplikuj, iba ak je novšie“) zvládnu to, čo predpoklady o poradí nezvládnu.

Zvyšok checklistu

Idempotencia je jadro; tri návyky okolo nej oddeľujú integrácie, ktoré prežijú produkciu, od tých, ktoré generujú tickety:

  • Potvrďte rýchlo, spracujte asynchrónne. Overte podpis, udalosť uložte, vráťte 200 a skutočnú prácu robte z fronty. Pomalé synchrónne handlery spôsobujú timeouty a timeouty spúšťajú ďalšie opakovania.
  • Autentifikujte každý webhook. Webhook endpoint je neautentifikovaná URL na verejnom internete, ktorá mení stav vášho biznisu. Väčšina poskytovateľov podpíše payload pomocou HMAC, ktorý si prepočítate a porovnáte; niektorí (GoPay) vám dajú len ID a očakávajú, že si smerodajný stav znova stiahnete z ich API. Tak či onak, nikdy nekonajte na základe surovej požiadavky tak, ako prišla.
  • Majte dead-letter queue s nástrojom na replay. Niektoré udalosti zlyhajú z dôvodov, ktoré opakovanie nevyrieši: zmazané SKU, diera v mapovaní. Odparkujte ich, alertujte na ne a z replayu jednej udalosti urobte tlačidlo, nie SSH session. Keď má API tretej strany výpadok, replay vám umožní dobehnúť zameškané bez vyhlasovania incidentu.

Test na všetko uvedené je jednoduchý: vezmite včerajšie udalosti zo stagingu a každú z nich doručte dvakrát, v premiešanom poradí. Ak koncový stav sedí s produkciou, vaša integrácia je naozaj idempotentná.

Toto je štandard, podľa ktorého integrácie staviame. Presne toto sa na našej stránke služieb skrýva za slovami „ustáť aj zlý deň API tretej strany“ a rovnaké uvažovanie sa objavuje v našom zákazkovom backendovom vývoji. A ak vaše čísla zásob už driftujú, webhooková vrstva je prvé miesto, kde hľadať.