Des webhooks vraiment fiables : doublons, timeouts et pics de trafic sur AWS et Azure
Un webhook fiable est un contrat opérationnel : réception rapide, persistance, déduplication, reprises contrôlées, DLQ et observabilité. Voici des modèles AWS et Azure pour des systèmes soumis à une charge réelle.
L’article complet est disponible ci-dessous. Activez JavaScript pour les quiz et les simulations.
Des webhooks vraiment fiables : doublons, timeouts et pics de trafic sur AWS et Azure
Un webhook est une frontière entre des systèmes distribués aux délais, garanties de livraison et tolérances très différents. C’est là que naissent ses pannes, au-delà du petit endpoint HTTP.
L’idée centrale
Un webhook fiable exige un parcours réfléchi : vérification, persistance, déduplication, file, reprises, dead-lettering, concurrence contrôlée et observabilité. Un contrôleur qui répond vite 200 ne suffit pas lorsque la production cesse d’être accommodante.
On traite souvent le webhook comme un endpoint REST ordinaire : réception, tout le métier, réponse. Ce modèle tient jusqu’au premier timeout, à la première reprise de l’émetteur, au premier pic ou au premier doublon.
En pratique, le webhook est un contrat opérationnel entre systèmes qui partagent rarement les mêmes garanties. L’un livre au moins une fois, l’autre attend exactement une fois. L’un réessaie agressivement, l’autre supporte mal les doublons. L’un émet en parallèle, l’autre suppose un ordre. C’est ici que commence le vrai travail d’architecture.
L’erreur courante : supposer qu’un succès HTTP signifie un succès métier. Ce n’est pas le cas.
Les enseignements essentiels
- Accuser rapidement réception et effectuer le travail lourd de façon asynchrone.
- Les doublons sont un état normal du distribué, pas une exception.
- L’ordre des événements doit être conçu explicitement.
- Des reprises sans idempotence ni DLQ repoussent la panne au lieu d’assurer la fiabilité.
- Sans identifiant d’événement, compteur de reprises et corrélation, le diagnostic devient une devinette.
Pourquoi les webhooks échouent en production
Une série de petites hypothèses suffit souvent à créer un incident coûteux :
- l’événement n’arrivera qu’une fois,
- les événements arriveront dans l’ordre,
- la dépendance répondra vite,
- le worker finira avant expiration du verrou ou du visibility timeout,
- un premier succès prouve que l’architecture est suffisante.
AWS et Azure proposent limitation d’entrée, files avec reprises, dead-lettering, fonctions idempotentes, concurrence contrôlée et récupération. Le problème apparaît lorsque ces mécanismes ne sont pas reliés dans une logique commune.
Un webhook stable est un ensemble de garanties
Il devrait appliquer des principes simples :
- Verify — vérifier signature, origine, horodatage et structure du message.
- Persist — enregistrer durablement l’événement ou son registre avant les effets secondaires.
- Deduplicate — faire de l’event ID une clé de l’architecture.
- Enqueue — séparer l’entrée HTTP du métier par une file ou un bus.
- Acknowledge fast — répondre rapidement 200/202 sans tout exécuter dans la requête.
- Process idempotently — rendre le worker sûr face aux reprises, doublons et rejeux.
- Dead-letter explicitly — confier les échecs à une récupération contrôlée.
- Observe everything — associer trace, métrique et corrélation aux étapes importantes.
Modèle de référence AWS
Un modèle entrant robuste sur AWS ressemble à ceci :
API Gateway → Lambda ingress → SQS → worker Lambda / ECS / Fargate → stockage + outbox + DLQ
Ce découpage organise les responsabilités.
1. API Gateway à l’entrée
La passerelle reçoit le trafic, filtre les abus évidents, limite le débit et maîtrise les pointes. Si l’entrée étouffe, la qualité du worker ne suffit pas.
2. Lambda ingress minimale
L’entrée évite le métier lourd : vérifier la signature, extraire l’event ID, enregistrer le registre d’idempotence, mettre en file et répondre vite.
3. SQS sépare les responsabilités
Choisissez Standard si débit et souplesse priment sur l’ordre strict. Choisissez FIFO lorsque l’ordre par agrégat compte réellement et que vous utilisez groupes et déduplication dans les garanties du modèle FIFO.
4. Le worker porte le métier
Mises à jour, effets secondaires, transitions d’état, outbox et confirmation contrôlée appartiennent ici. Le worker ne suppose ni première livraison ni ordre idéal.
5. La DLQ comme couche opérationnelle
La dead-letter queue conserve les cas que le système n’a pas pu achever automatiquement. Elle fournit le matériau d’analyse, de rejeu, de correction et d’amélioration.
Modèle de référence Azure
Une approche cohérente sur Azure ressemble à ceci :
Front Door / API Management → Azure Functions HTTP trigger → Service Bus → Function worker / Container Apps / AKS → stockage + DLQ + Application Insights
1. API Management ou Front Door en entrée
Cette couche limite les pics, applique des politiques et protège le backend d’un afflux soudain.
2. Azure Functions comme entrée légère
Le déclencheur HTTP ne doit pas tout faire : réception, vérification, enregistrement, publication vers Service Bus et réponse constituent son rôle.
3. Service Bus porte reprises et ordre
Les sessions conviennent au traitement ordonné d’une entité. La détection de doublons apporte une protection supplémentaire sans supprimer le besoin d’idempotence des workers.
4. Worker et métier
Azure Functions, Container Apps ou AKS : la technologie vient après les principes. Le worker résiste aux reprises, échecs partiels, nouvelles livraisons et effets déjà produits avant la confirmation.
5. Application Insights et DLQ
Il faut voir tout le parcours, de l’entrée HTTP au résultat métier via Service Bus. Sans cela, la stabilité reste une espérance.
Le principe de conception essentiel
L’entrée reçoit, vérifie, persiste, déduplique, met en file et répond. Les opérations coûteuses, longues ou porteuses d’effets secondaires se déroulent hors du cycle HTTP.
L’idempotence, fondation des reprises sûres
Puisqu’un webhook peut revenir, il faut un modèle explicite :
- provider event ID devient la clé de déduplication,
- l’entrée effectue un insert-if-absent dans le registre des événements reçus,
- seule la première écriture met la suite du travail en file,
- le worker exécute les effets sous condition, pas aveuglément,
- une répétition reçoit une réponse technique sans doubler le métier.
C’est ce qui sépare une reprise supportée d’une seconde commande, d’un second e-mail ou d’une seconde expédition.
// pseudokod ingressu webhooka
verifySignature(rawBody, headers.signature, secret)
const providerEventId = headers["x-event-id"] || body.id
const dedupeKey = `${provider}:${providerEventId}`
const inserted = inboxStore.insertIfAbsent({
dedupeKey,
payloadHash: sha256(rawBody),
receivedAt: now()
})
if (!inserted) {
return http(200, { ok: true, duplicate: true })
}
queue.publish({
dedupeKey,
eventType: body.type,
aggregateId: body.orderId || body.customerId,
payloadRef: payloadStore.save(rawBody)
})
return http(202, { ok: true })
L’ordre : ne le supposez pas sans l’imposer
« Les webhooks arriveront dans l’ordre » est une illusion coûteuse. Rien ne le garantit spontanément.
Avec un flux de type :
ORDER_CREATEDORDER_PAIDORDER_CANCELLED
le système peut revoir ORDER_PAID, recevoir ORDER_CANCELLED avant d’avoir traité l’événement précédent, ou rejouer un ancien message après reprise.
Si l’ordre compte, exprimez-le dans l’architecture :
- sur AWS avec SQS FIFO + MessageGroupId = aggregateId,
- sur Azure avec Service Bus Sessions + SessionId = aggregateId.
La file organise l’ordre technique, mais le domaine doit encore protéger l’ordre métier. Un état ancien ne doit pas écraser un état récent parce qu’il est arrivé plus tard.
Reprises, backoff et DLQ : sans politique, la panne est seulement différée
Réessayer est nécessaire, mais ne constitue pas une stratégie complète.
Un modèle mature :
- ne répète que les erreurs plausiblement transitoires,
- borne les tentatives et la durée de vie de l’événement,
- transfère ensuite en DLQ avec le contexte complet.
Sinon, le système fait circuler les mêmes erreurs jusqu’à aggraver la situation de la dépendance.
Une DLQ montre que l’architecture ne prétend pas à un succès inexistant.
Trois scénarios réalistes qui révèlent une architecture fragile
1. Le webhook de paiement revient
Le fournisseur envoie payment.succeeded. Votre système enregistre la transaction, modifie la commande et envoie l’e-mail. La réponse tarde ou se perd. Le fournisseur réessaie. Sans idempotence, vous dupliquez e-mail, expédition ou écriture comptable.
Le modèle est clair : event ID comme clé, insert-if-absent à l’entrée, premier enregistrement seul déclencheur et effets conditionnels dans le worker.
2. Les statuts logistiques arrivent dans le mauvais ordre
Vous recevez les événements : shipment.created, shipment.picked_up, shipment.in_transit, shipment.delivered. Si delivered arrive plus tôt ou si un ancien événement est rejoué, l’état devient incohérent. La déduplication seule ne suffit pas : il faut ordonner par entité et valider les transitions.
3. Webhooks sortants vers des clients peu fiables
La plateforme envoie à des centaines ou milliers de tenants. Certains répondent vite ; d’autres renvoient 429. Certains prennent plusieurs secondes, d’autres ont un 500instable. Un dispatch commun laisse un client défaillant nuire aux autres. Il faut isolation des tenants, backpressure, reprises, DLQ et délais de connexion fermes.
Points de vigilance
- Ne considérez pas 2xx comme une réussite métier.
- N’exécutez pas le travail lourd dans la requête du webhook.
- Ne reportez pas l’idempotence.
- Ne supposez pas un ordre non imposé.
- Traitez la DLQ comme une partie de la fiabilité.
- Journalisez event ID, tenant, agrégat, nombre de reprises et résultat final, pas seulement « webhook reçu ».
- Isolez un destinataire défaillant du reste du pipeline sortant.
Observabilité : sans corrélation, le diagnostic devient une supposition
Pendant un incident, pouvez-vous déterminer :
- première réception ou doublon,
- passage éventuel en DLQ,
- nombre de reprises,
- échec de l’entrée, de la file ou du worker,
- transformation du succès technique en succès métier ?
Sinon, le système reste opaque.
Un ensemble minimal de champs utiles dans les journaux et métriques :
provider_event_iddedupe_keytenant_idaggregate_idsignature_verifiedingress_latency_msqueue_enqueue_latency_msworker_processing_latency_msretry_countdead_letter_reasonfinal_business_outcome
Liste de contrôle de l’architecte webhook
- L’événement possède-t-il un identifiant stable et non ambigu ?
- Vérifiez-vous signature et horodatage avant la suite ?
- Persistez-vous l’événement avant les effets ?
- Avez-vous insert-if-absent ou un autre registre d’idempotence ?
- L’entrée répond-elle vite et de façon prévisible ?
- Le worker résiste-t-il aux reprises, rejeux et échecs partiels ?
- L’ordre par agrégat est-il explicite ?
- Les reprises sont-elles bornées avec une DLQ ensuite ?
- Pouvez-vous réinjecter de manière contrôlée depuis la DLQ ?
- La corrélation couvre-t-elle l’entrée jusqu’au résultat métier ?
L’importance pour l’activité
Un webhook fragile dégrade paiements, commandes, communication et déclenchement des processus. Il surcharge les dépendances et crée une dette révélée par la croissance du trafic.
Un bon webhook est avant tout prévisible. Cette prévisibilité réduit concrètement le coût d’une automatisation défaillante.
La question essentielle de l’équipe
Notre webhook résiste-t-il vraiment aux doublons, reprises, timeouts et pointes, ou n’avons-nous simplement pas encore rencontré le cas révélateur ?
Ce qui compte finalement
La fiabilité concerne tout le parcours : réception, registre, déduplication, file, worker, reprises, DLQ et effet métier final.
Les meilleurs webhooks sont sobres, prévisibles et robustes. C’est exactement ce qu’on attend d’eux.
Chez ArcCloud, nous regardons l’intégration comme une suite de décisions opérationnelles : accepté, confirmé, à reprendre, en DLQ, à traiter manuellement. La stabilité commence lorsque l’on cesse de deviner.
Sources techniques
- AWS API Gateway : limitation du débit et 429
- AWS SQS : Standard, FIFO, ordre et déduplication
- AWS SQS MessageDeduplicationId
- AWS SQS MessageGroupId
- AWS Lambda + SQS : visibility timeout et scaling
- AWS Lambda : concurrence
- AWS Lambda : idempotence et bonnes pratiques
- AWS EventBridge : reprises et DLQ
- AWS EventBridge API Destinations : timeout et débit
- Azure Functions : timeout HTTP et mise à l’échelle
- Azure Functions : déclencheur HTTP
- Azure Functions : idempotence
- Azure Functions : concurrence
- Azure Service Bus : détection des doublons
- Azure Service Bus : sessions et FIFO
- Azure Service Bus : DLQ
- Azure Event Grid : validation de l’endpoint
- Azure Event Grid : livraison, reprises et dead-lettering
- Azure API Management : limitation du débit