Produktionssäker webhook-arkitektur. Retry, idempotens och DLQ.
Webhooks är bedrägligt enkla. Du registrerar en URL, en annan tjänst gör en POST när något händer, och du är klar - tills den dagen er mottagare är nere i tio minuter, eller samma order plötsligt skapas tre gånger, eller en betalning aldrig bokförs och ingen vet varför. De flesta webhook-integrationer jag får i uppdrag att rädda föll inte på själva mottagningen, utan på allt runt omkring: vad som händer när det går fel.
Den här djupdykningen handlar om de tre sakerna som skiljer en demo från en webhook-arkitektur som håller i produktion: retry, idempotens och dead letter queues. Den typen av robusthet bygger jag in från start inom systemintegration.
Ta emot snabbt, bearbeta asynkront
Det enskilt vanligaste felet är att göra allt arbete inne i webhook-handtaget innan man svarar. Avsändaren har en timeout, ofta bara några sekunder. Hinner ni inte svara inom den tiden tror avsändaren att leveransen misslyckades och skickar om - trots att ni faktiskt tog emot. Resultatet blir dubbelarbete och förvirring.
Lösningen är att skilja mottagning från bearbetning. Webhook-handtaget ska göra ett minimum: verifiera signaturen, lägga händelsen på en kö och omedelbart svara 200. Den tunga bearbetningen sker sedan av en separat arbetare som läser från kön i egen takt. Då blir er svarstid förutsägbart låg oavsett hur långsam den underliggande affärslogiken är, och ni slutar trigga onödiga omsändningar.
Retry: anta att leveransen kommer att misslyckas
Nätverk fallerar, mottagare startar om, databaser är tillfälligt otillgängliga. En robust arkitektur behandlar misslyckanden som det normala, inte undantaget. Det innebär omförsök med exponentiell backoff - vänta längre och längre mellan försöken i stället för att hamra direkt - gärna med jitter, en liten slumpmässig variation som hindrar att tusen samtidiga händelser försöker igen i exakt samma sekund och slår ut mottagaren när den precis kommit tillbaka.
Lika viktigt är att skilja på fel som är värda att försöka igen och fel som inte är det. En 500:a eller timeout är övergående - försök igen. En 400:a på grund av en felformad payload kommer aldrig att lyckas hur många gånger ni än försöker - då ska händelsen direkt vidare till en dead letter queue i stället för att slösa försök. Att blanda ihop de två är ett klassiskt sätt att antingen tappa data eller bygga en oändlig retry-loop.
Idempotens: samma händelse två gånger får inte bli två resultat
Eftersom ni gör omförsök kommer samma händelse förr eller senare att tas emot mer än en gång. Det är inte ett edge case, det är en garanti. Därför måste bearbetningen vara idempotent: att hantera samma händelse två gånger ska ge exakt samma sluttillstånd som att hantera den en gång.
I praktiken löser jag det med en idempotensnyckel. Varje händelse bär ett unikt id, och innan jag bearbetar den kollar jag om det id:t redan är hanterat - om så är fallet kvitterar jag och gör inget mer. Nyckeln lagras tillsammans med resultatet, ofta med en lämplig livslängd. Det här är skillnaden mellan en kund som debiteras en gång och en kund som debiteras tre gånger, och det är inget man lägger till i efterhand utan smärta. Bygg in det från början.
Dead letter queues: ett synligt slut för det som inte går
När en händelse har misslyckats efter alla rimliga omförsök får den inte bara försvinna. En dead letter queue, DLQ, är en separat kö dit sådana händelser flyttas - med hela sin payload och felhistorik bevarad. Poängen är dubbel: den skyddar resten av flödet från att fastna bakom en enstaka giftig händelse, och den gör problemet synligt i stället för tyst.
En DLQ är värdelös om ingen tittar på den. Därför hör larm ihop med den: växer DLQ:n ska någon få veta. Och ni behöver en väg att återspela händelser därifrån när ni rättat grundorsaken, så att ingen affärshändelse går förlorad. Jag ser DLQ:n som integrationens säkerhetsnät - det är där ni upptäcker problemen innan kunden gör det.
Observabilitet och säkerhet binder ihop det
Två saker till gör arkitekturen förvaltningsbar. Verifiera alltid avsändarens signatur så att ni vet att anropet är äkta och inte någon som hittat er endpoint. Och logga varje händelses resa - mottagen, bearbetad, omförsökt, hamnad i DLQ - med korrelations-id, så att ni kan svara på frågan "vad hände med order 4711?" på sekunder i stället för timmar. Ett verkligt exempel på en sådan ombyggnad finns i kundcase. Hela upplägget kan jag bygga med er inom systemintegration.
Relaterat
- Event-driven arkitektur med Kafka vs RabbitMQ vs AWS EventBridge
- API-first arkitektur: REST vs GraphQL vs gRPC vs tRPC beslutsguide
- GraphQL Federation: Microservices med ett enhetligt API-lager
Vill du ta det vidare?
Jag bygger och rättar webhook-arkitekturer som överlever verkligheten - med retry, idempotens och DLQ som standard, inte som efterhandskonstruktion. Boka ett förutsättningslöst samtal så går vi igenom era integrationer.
“En robust arkitektur behandlar misslyckanden som det normala, inte undantaget. Webhooken som inte tål att mottagaren är nere är inte färdig.”
- Simon Axelsson
Vanliga frågor
- Varför ska webhook-handtaget svara innan det bearbetar?
- För att avsändaren har en kort timeout. Gör du allt arbete före svaret riskerar du att överskrida den, varpå avsändaren tror att leveransen misslyckades och skickar om. Kvittera med 200 direkt, lägg händelsen på en kö och bearbeta asynkront.
- Vad är idempotens i webhook-sammanhang?
- Att hantera samma händelse flera gånger ger samma sluttillstånd som att hantera den en gång. Eftersom omförsök garanterar dubbletter använder man en unik idempotensnyckel per händelse och hoppar över bearbetning om nyckeln redan är sedd.
- Behöver vi verkligen en dead letter queue?
- Om ni bryr er om att inte tyst tappa affärshändelser, ja. En DLQ fångar det som misslyckats efter alla omförsök, skyddar resten av flödet och låter er återspela händelserna när grundorsaken är rättad. Komplettera den med larm så att någon faktiskt ser när den växer.
Simon Axelsson är senior IT-konsult och grundare av SIAX Technology AB. Han hjälper nordiska företag med molninfrastruktur, dataplattformar och AI-automation.
Fler artiklar