Praktický návod
Jak zabránit duplicitnímu zpracování platby nebo objednávky
Stejná událost může dorazit dvakrát. To je normální. Aplikace musí umět bezpečně říct: už jsem ji zpracovala.
Nejdřív stručně
Proč se duplicity dějí?
Webhook nebo jiná externí zpráva se může opakovat kvůli výpadku sítě, pomalé odpovědi nebo automatickému opakování. Dvakrát může kliknout i člověk.
Idempotence znamená, že stejná operace dopadne stejně, i když ji aplikace dostane opakovaně. U platby to často znamená: jedna platba, jedna objednávka, jeden e-mail.
Připrav si
Co musíš znát
Nehledej duplicitu podle času nebo částky. Potřebuješ stabilní identifikátor stejné události.
- ID události od platební brány nebo vlastní jedinečný klíč pro požadavek.
- Místo v databázi, kde si uložíš, že událost už přišla.
- Jednoznačné pravidlo, co se má stát při druhém doručení: nic znovu nevytvářet, jen bezpečně vrátit výsledek.
- Testovací událost, kterou můžeš poslat dvakrát bez skutečného stržení peněz.
Krok 1
Postav ochranu ve třech vrstvách
Nespoléhej jen na kontrolu v kódu. Dvě stejné žádosti mohou přijít ve stejném okamžiku.
1. Vyber správný klíč
- Použij ID události od poskytovatele platby. Pro vlastní akci vytvoř klíč při jejím začátku a posílej ho s požadavkem.
- Klíč musí zůstat stejný při opakování stejné události. Nový pokus o jinou platbu musí mít nový klíč.
- Neodvozuj ho z ceny, e-mailu nebo času. Tyto hodnoty nejsou dostatečně jedinečné.
2. Ulož klíč s jedinečným pravidlem
- Vytvoř záznam zpracované události s jejím ID a výsledkem.
- Na ID nastav jedinečné omezení v databázi. To je poslední pojistka, když dva požadavky projdou kontrolou současně.
- Uložení události i změnu objednávky udělej v jedné databázové transakci.
3. Druhé doručení ukonči bezpečně
- Pokud klíč už znáš, nevytvářej další platbu, objednávku ani e-mail.
- Vrať úspěšnou odpověď nebo výsledek původního zpracování. Odesílatel pak nemusí zkoušet další opakování.
- Zapiš, že šlo o duplicitu. Při ladění pak poznáš, že ochrana funguje.
Krok 2
Ověř ochranu dvěma pokusy
Jeden úspěšný požadavek nestačí. Potřebuješ vidět, co se stane při jeho opakování.
-
Pošli stejnou událost dvakrát
Použij stejné ID události. Oba požadavky mohou skončit úspěšně, ale v databázi smí vzniknout jen jeden výsledek.
-
Zkontroluj vedlejší účinky
Ověř počet plateb, objednávek i e-mailů. Nesmí přibýt druhý záznam ani druhé oznámení.
-
Vyzkoušej souběh
Pošli stejnou událost současně ze dvou požadavků. Právě tady musí ochránit jedinečné pravidlo a transakce.
Když to zlobí
Nejčastější chyby
Kontrola funguje při jednom požadavku, ale ne při souběhu
Pouhé „nejdřív zkontroluji, pak vložím“ nestačí. Dva požadavky mohou kontrolu projít současně. Potřebuješ jedinečné databázové omezení.
Platba se uložila, ale objednávka ne
Související změny ukládej společně v databázové transakci. Když jedna část selže, data se nemají tvářit jako hotová.
Aplikace odmítá i jinou platbu jako duplicitu
Nejspíš znovu používáš stejný klíč pro různé události. Zkontroluj, že každá nová platba nebo objednávka dostane vlastní stabilní ID.
Neověřený webhook mění stav objednávky
Nejdřív ověř původ příchozího webhooku podle pravidel poskytovatele. Teprve potom ulož jeho ID a spusť zpracování.
Hotovo
Druhý pokus už nenadělá škodu.
Idempotence chrání zákazníka i tebe. U důležitých událostí ji ber jako běžnou součást návrhu, ne jako pozdější opravu.