Nouvelles tentatives et ordre
Ce qui se passe quand votre endpoint est en panne, et pourquoi un événement arrive deux fois.
Votre endpoint tombera en panne un jour ou l'autre, et Wajub fera de nouvelles tentatives. C'est la partie facile. La partie difficile, c'est qu'une nouvelle tentative exécute votre handler une seconde fois sur un événement qu'il a peut-être déjà traité, et s'il expédie une commande à chaque exécution, il l'expédie deux fois.
Cette page couvre ce que Wajub garantit, ce qu'il ne garantit pas, et la forme de handler qui résiste aux deux.
Ce que Wajub garantit
Au moins une fois, pas exactement une fois. Chaque événement atteint votre endpoint au moins une fois. Certains l'atteindront plusieurs fois. Concevoir pour une livraison exactement une fois, c'est concevoir pour quelque chose qu'aucun système de webhooks ne fournit.
Deux cas rares font plier cette promesse, et il faut connaître les deux :
- Un événement peut arriver en retard, ou avec une partie seulement de ses données. Rarement,
un événement vous parvient après des événements survenus plus tard, ou avec un
dataqui ne contient que l'idet l'objectde l'objet. Dans ce cas, lisez l'objet dans l'API. - Les livraisons s'arrêtent tant que Wajub restreint vos webhooks, dans le cadre d'une
restriction de votre compte ou de sa fermeture. Les événements sont toujours enregistrés et listés
par
GET /events, mais aucun n'est envoyé, ni à vos endpoints ni àwajub listen. Les événements enregistrés pendant la restriction ne sont pas envoyés quand elle est levée : lisez-les avecGET /eventset rejouez ceux dont vous avez besoin avecPOST /events/{id}/resend.
C'est pourquoi un rapprochement quotidien fait partie de toute intégration : ce n'est pas un filet de sécurité facultatif. Voir La page de retour n'est pas une confirmation.
Aucune garantie d'ordre. Les événements sont livrés au fur et à mesure de leur production, avec
des nouvelles tentatives intercalées. Un payment.succeeded peut arriver avant le
payment.processing qui l'a précédé. Ne déduisez jamais l'état d'un paiement de l'ordre d'arrivée
des événements. Lisez l'état dans le corps de l'événement, ou récupérez le paiement.
Quand une livraison compte comme un échec
Une livraison réussit quand votre endpoint répond avec n'importe quel 2xx en moins de
10 secondes. Toute autre issue est un échec.
| Votre réponse | Ce qui se passe |
|---|---|
2xx | Livré. Rien de plus. |
5xx, ou une erreur réseau | Nouvelle tentative, selon le calendrier ci-dessous |
N'importe quel 4xx | Nouvelle tentative, selon le calendrier ci-dessous |
410 Gone | Aucune nouvelle tentative. Votre endpoint indique qu'il n'acceptera jamais cet événement |
| Aucune réponse en 10 secondes | Nouvelle tentative |
Une redirection 3xx | Nouvelle tentative. Les redirections ne sont jamais suivies, une redirection n'aboutit donc jamais à une livraison |
Seul un 410 met fin à la livraison
Un 400 ou un 404 est retenté comme un 500 : un endpoint qui répond 404 pendant un
déploiement reçoit quand même l'événement une fois revenu. Renvoyez 410 uniquement quand vous
voulez que Wajub arrête définitivement cette livraison, et 2xx dès que vous l'avez reçue.
Le calendrier des nouvelles tentatives
Wajub continue d'essayer pendant 72 heures après la première tentative. Il n'y a pas de nombre fixe de tentatives. L'attente commence à 30 secondes et double après chaque échec, jusqu'à 6 heures. Chaque attente est tirée au hasard entre la moitié et la totalité de cette valeur, pour qu'un endpoint qui redémarre après une panne ne reçoive pas toutes les nouvelles tentatives au même instant.
| Après l'échec de la tentative | Tentative suivante dans |
|---|---|
| 1 | 15 à 30 secondes |
| 2 | 30 à 60 secondes |
| 3 | 1 à 2 minutes |
| 4 | 2 à 4 minutes |
| 5 | 4 à 8 minutes |
| 6 | 8 à 16 minutes |
| 7 à 10 | l'attente continue de doubler |
| 11 et au-delà | 3 à 6 heures |
Une fois les 72 heures écoulées, la livraison est marquée failed et Wajub s'arrête. Votre endpoint
n'est pas désactivé : le prochain événement sera quand même tenté, et vous pouvez rejouer à la
main celui qui a échoué depuis Konsole ou avec POST /events/{id}/resend. Si vous supprimez ou
désactivez l'endpoint pendant qu'une livraison est encore retentée, les tentatives restantes sont
abandonnées.
Dédupliquer : deux clés, deux significations
Chaque livraison porte les deux. Elles ne sont pas interchangeables, et choisir la mauvaise produit un bug que vous ne verrez pas avant d'ajouter un second endpoint.
id dans le corps, une valeur evt_…, identifie l'événement. Il est identique à chaque
nouvelle tentative, et identique pour chaque endpoint qui reçoit cet événement.
X-Wajub-Delivery-Id dans les en-têtes, une valeur whd_…, identifie la livraison vers un
endpoint. Il reste stable sur toutes les tentatives, renvoi manuel compris, et diffère pour chaque endpoint.
Laquelle stocker
Dédupliquez sur l'id du corps quand le traitement doit avoir lieu une fois par événement métier,
ce qui est presque toujours le cas : expédier une commande, créditer un compte, envoyer un reçu.
Utilisez X-Wajub-Delivery-Id quand vous suivez la santé des livraisons par endpoint plutôt que
les effets métier.
La forme du handler
Quatre étapes, dans cet ordre. Tout l'enjeu est dans l'ordre.
# The same event, arriving a second time after a timeout.
# Body id and delivery id are both the ones of the first attempt.
X-Wajub-Delivery-Id: whd_7Yh2MpL4tRb3nP8sZcXv
{"id":"evt_aio5DpN577tNU2vOxdmuZGhT","event":"payment.succeeded","data":{…}}200 signifie reçu, pas traité
Accusez réception dès l'arrivée et traitez de façon asynchrone. Si votre propre traitement peut échouer, relancez-le depuis votre propre file de tâches. Compter sur les nouvelles tentatives de Wajub pour rejouer votre logique métier la fait attendre un calendrier qui monte à plusieurs heures entre deux tentatives, et s'arrête au bout de 72 heures.
Marquez l'événement comme traité avant d'effectuer le travail, pas après. Si vous le marquez après, deux nouvelles tentatives arrivées à peu d'intervalle peuvent toutes deux passer la vérification et toutes deux s'exécuter.
Rapprocher l'événement de la requête qui l'a provoqué
Le corps contient la requête qui a produit l'événement :
request décrit l'enregistrement de l'événement, pas votre appel API. request.id vaut null, et
request.idempotency_key est une valeur idem_… générée au moment où l'événement a été stocké.
Aucun des deux ne vous renvoie l'en-tête Idempotency-Key que vous avez envoyé.
Associez plutôt un événement à une commande grâce à la ressource : data.reference est la
reference que vous avez fournie à la création du paiement, et data.metadata est à votre
disposition. Les deux survivent à chaque nouvelle tentative, car ils font partie de la ressource et
non de la livraison.
`livemode`, pas `sandbox`
L'enveloppe du webhook utilise livemode, qui est l'inverse du champ sandbox renvoyé par
l'API REST. Un événement sandbox porte "livemode": false.
api_version est la version courante de la plateforme au moment où l'événement a été enregistré,
et le corps suit la forme de cette version. Fixer votre compte ou une requête sur une version plus
ancienne change ce que renvoient vos appels API, jamais ce que reçoit votre endpoint.
Inspecter et rejouer
Chaque tentative est enregistrée avec son code de statut, son corps de réponse et sa latence dans Konsole. Une fois votre endpoint corrigé, vous pouvez rejouer une seule livraison, ou jusqu'à 100 livraisons échouées d'un coup, avec le payload d'origine et un en-tête fraîchement signé.
Chaque livraison rejouée est décomptée d'un quota mensuel fixé par votre offre : 5 en Pay as you go,
25 en Growth, voir Limites. POST /events/{id}/resend envoie l'événement à
chaque endpoint qui ne l'a pas encore accepté.
Webhook deliveries
| Method | Endpoint | Status | Duration | Attempt |
|---|---|---|---|---|
| POST | /webhooks/wajub | 500 | 10021 ms | 1 |
| POST | /webhooks/wajub | 500 | 240 ms | 2 |
| POST | /webhooks/wajub | 200 | 142 ms | 3 |
Pages associées
- Vérification de signatureVérifiez le HMAC avant de faire confiance à un payload.
- Catalogue des événementsTous les types d'événements émis par Wajub.
- Cycle de vie d'un paiementLes états qui émettent un événement, et ceux qui n'en émettent pas.
- Tester les webhooksRecevez des événements en local sans déployer.