GH GambleHub

Garanties de livraison de webhooks

Webhooks - notifications asynchrones « du système à l'abonné » par HTTP (S). Le réseau n'est pas fiable : les réponses sont perdues, les paquets sont dupliqués ou hors d'ordre. C'est pourquoi les garanties de livraison ne sont pas construites « par TCP », mais au niveau du protocole Web et de l'idempotence du domaine.

L'objectif principal est de fournir une livraison at-least-once avec un ordre par clé (le cas échéant), de donner à l'abonné du matériel pour le traitement idempotent et un outil de récupération.


1) Niveaux de garantie

Best-effort est une tentative unique, sans retraits. Seulement acceptable pour les événements « sans importance ».
At-least-once (recommandé) - les doublons et out-of-order sont possibles, mais l'événement sera livré sous réserve de la disponibilité de l'abonné dans un délai raisonnable.
Effectively-exactly-once (au niveau de l'effet) - obtenu par une combinaison d'idempotence et de dedup-store du côté abonné/expéditeur. Dans les transports HTTP, « exactly-once » n'est pas possible.


2) Contrat Webhook : minimum nécessaire

Titres (exemple) :

X-Webhook-Id: 5d1e6a1b-4f7d-4a3d-8b3a-6c2b2f0f3f21  # глобальный ID события
X-Delivery-Attempt: 3                 # номер попытки
X-Event-Type: payment.authorized.v1          # тип/версия
X-Event-Time: 2025-10-31T12:34:56Z          # ISO8601
X-Partition-Key: psp_tx_987654            # ключ порядка
X-Seq: 418                      # монотонный номер по ключу
X-Signature-Alg: HMAC-SHA256
X-Signature: t=1730378096,v1=hex(hmac(secret, t        body))
Content-Type: application/json
Corps (exemple) :
json
{
"id": "5d1e6a1b-4f7d-4a3d-8b3a-6c2b2f0f3f21",
"type": "payment.authorized.v1",
"occurred_at": "2025-10-31T12:34:56Z",
"partition_key": "psp_tx_987654",
"sequence": 418,
"data": {
"payment_id": "psp_tx_987654",
"amount": "10.00",
"currency": "EUR",
"status": "AUTHORIZED"
},
"schema_version": 1
}

Exigence pour le destinataire : répondre rapidement '2xx' après la mise en tampon et la validation de la signature, et le traitement de l'entreprise est asynchrone.


3) Ordre et causalité

Ordre par clé : la garantie « ne partira pas » à l'intérieur d'un seul 'partition _ key' (par exemple, 'player _ id', 'wallet _ id', 'psp _ tx _ id').
L'ordre mondial n'est pas garanti.
Du côté de l'expéditeur, il y a une file d'attente avec sérialisation par clé (un consommateur/Charding), du côté du destinataire, inbox avec '(source, event_id)' et l'attente facultative des 'seq' manqués.

Si les omissions sont critiques - fournir pull-API 'GET/events ? after = checkpoint 'pour le statut « rattraper et vérifier ».


4) Idempotence et déduplication

Chaque webhook porte un "X-Webhook-Id'stable.
Le destinataire stocke 'inbox (event_id)' : PK - 'source + event_id' ; répétitions → no-op.
Les effets secondaires (enregistrement dans la base de données/portefeuille) ne se produisent qu'une seule fois lors de la première « vision » de l'événement.
Pour les commandes à effet, utilisez Idempotency-Key et le cache des résultats pendant la fenêtre de retraits.


5) Retrai, backoff et fenêtres

Politique de retraite (référence) :
  • Rétracter sur '5xx/timeout/connection error/409-Conflict (retryable )/429'.
  • Ne pas rétracter sur '4xx' sauf '409/423/429' (et uniquement avec la sémantique convenue).
  • Backoff exponentiel + full jitter : 0. 5s, 1s, 2s, 4s, 8s, … jusqu'à « max = 10-15 min » ; Fenêtre de rétraction TTL : par exemple 72 heures.
  • Respecter 'Retry-After' chez le destinataire.
  • Avoir une date limite commune : « reconnaître un événement non livré » et le traduire en DLQ.
yaml retry:
initial_ms: 500 multiplier: 2.0 jitter: full max_delay_ms: 900000 ttl: 72h retry_on: [TIMEOUT, 5xx, 429]

6) DLQ и redrive

DLQ est un « cimetière » d'événements toxiques ou expirés par TTL avec une métainformation complète (paload, titres, erreurs, tentatives, hachages).
Console Web/API pour redrive (refonte ponctuelle) avec modification en option de endpoint/secret.
Rate-limited redrive et batch-redrive avec priorité.


7) Sécurité

mTLS (si possible) ou TLS 1. 2+.

Signature du corps (HMAC avec secret per tenant/endpoint). Vérification :

1. Extraire 't' (timestamp) de l'en-tête, vérifier la fenêtre glissante (par exemple, ± 5 min).

2. Restaurer la chaîne de signature 'tbody ', comparer HMAC en constant-time.
Anti-replay : stocker '(event_id, t)' et rejeter les requêtes trop anciennes/répétées.
Rotation des secrets : soutien de deux secrets actifs pendant la période de rotation.
En option : IP-allowlist, en-tête 'User-Agent', dédicace origin-IP.

8) Quotas, taux limites et équité

Fair-Queue per tenant/subscriber : qu'un abonné/ténant ne marque pas le pool partagé.
Quotas et limites burst pour le trafic sortant et per-endpoint.
Réaction à '429' : honorer 'Retry-After', noyer le flux ; avec une limite longue - degrade (envoyer uniquement les types d'événements critiques).


9) Cycle de vie de l'abonnement

Register/Verify : POST endpoint → challenge/response ou out-of-band confirmation.
Lease (si désiré) : la signature est valable jusqu'à « valid _ to » ; la prolongation est explicite.
Secret rotation: `current_secret`, `next_secret` с `switch_at`.
Test ping : événement artificiel pour vérifier l'itinéraire avant d'allumer les tops principaux.
Échantillons de santé : HEAD/GET périodiques avec contrôle de latitude et profil TLS.


10) Évolution des schémas (versions des événements)

Versioner le type d'événement : 'payment. authorized. v1` → `…v2`.
Évolution - additive (nouveaux champs → version MINOR de l'API), breaking → nouveau type.
Registre des schémas (JSON-Schema/Avro/Protobuf) + validation automatique avant l'envoi.
L'en-tête « X-Event-Type » et le champ « schema _ version » dans le corps sont obligatoires.


11) Observabilité et SLO

Métriques (par type/tenant/abonné) :
  • `deliveries_total`, `2xx/4xx/5xx_rate`, `timeout_rate`, `signature_fail_rate`.
  • 'attempts _ avg ',' p50/p95/p99 _ delivery _ latency _ ms' (de la publication à 2xx).
  • `dedup_rate`, `out_of_order_rate`, `dlq_rate`, `redrive_success_rate`.
  • `queue_depth`, `oldest_in_queue_ms`, `throttle_events`.
SLO (référence) :
  • La part des livraisons ≤ 60 c (p95) est de 99. 5 % pour les événements critiques.
  • DLQ ≤ 0. 1 % en 24 heures
  • Signature failures ≤ 0. 05%.

Логи/трейсинг: `event_id`, `partition_key`, `seq`, `attempt`, `endpoint`, `tenant_id`, `schema_version`, `trace_id`.


12) Algorithme de référence de l'expéditeur

1. Enregistrez l'événement dans un outbox transactionnel.
2. Identifier les partition_key et les seq ; mettre en file d'attente.
3. Worker prend par clé, forme une requête, signe, envoie avec des temporisations (connect/read).
4. Avec '2xx' - reconnaître livré, enregistrer la latence et seq-chekpoint.
5. Avec '429/5xx/timeout', c'est une rétrospective selon la politique.
6. Par TTL → DLQ et alert.


13) Processeur de référence (destinataire)

1. Accepter la demande, vérifier TLS/proto.
2. Validation de la signature et de la fenêtre temporelle.
3. ACK 2xx rapide (après écriture synchrone dans l'inbox/file d'attente locale).
4. Le worker asynchrone lit 'inbox', vérifie 'event _ id' (dedup), si nécessaire, ordonne par 'seq' à l'intérieur de 'partition _ key'.
5. Exécute des effets, écrit « offset/seq chekpoint » pour reconcile.
6. En cas d'erreur, les retraits locaux ; les tâches « toxiques » → un DLQ local avec des alertes.


14) Reconcile (circuit pull)

Pour les incidents « non résolus » :
  • `GET /events? partition_key=...&after_seq=...&limit=...' - donner tous les manquants.
  • Token-chekpoint : 'after = opaque _ token' au lieu de seq.
  • Idempotent redelivery : même 'event _ id', même signature pour le nouveau 't'.

15) Titres et codes utiles

2xx - accepté (même si le traitement de l'entreprise est plus tard).
410 Gone - endpoint fermé (l'expéditeur arrête la livraison et marque l'abonnement comme « archive »).
409/423 - Blocage temporaire de la ressource → rétrospective raisonnable.
429 - trop souvent → TNT et backoff.
400/401/403/404 - erreur de configuration ; arrêtez les retraits, ouvrez le tiquet.


16) Multi-tenants et régions

Files d'attente séparées et limites per tenant/endpoint.
Data residency : envoi depuis la région de données ; les titres de passage « X-Tenant », « X-Région ».
Isolation des pannes : la chute d'un abonné n'affecte pas les autres (separate pools).


17) Tests

Tests de contrat : exemples fixes de corps/signatures, vérification de validation.
Chaos : drop/doublons, ordre shuffle, retards réseau, « RST », « TLS ».
Load : tempête burst, mesure p95/p99.
Sécurité : anti-relais, timestamp obsolète, secrets erronés, rotation.
DR/Replay : masse redrive de DLQ dans un stand isolé.


18) Pleybooks (runbooks)

1. Croissance de 'signature _ fail _ rate'

Vérifier la dérive de l'horloge qui a expiré 'tolerance', la rotation des secrets ; inclure temporairement « dual secret ».

2. La file d'attente vieillit ('oldest _ in _ queue _ ms' ↑)

Augmenter les workers, activer la priorité des axes critiques, réduire temporairement la fréquence des types « bruyants ».

3. Tempête '429' chez l'abonné

Activer le câblage et les pauses entre les tentatives ; déplacer les types d'événements moins critiques.

4. Masse '5xx'

Ouvrir le circuit-breaker pour un endpoint spécifique, le mettre en mode defer & batch ; signal à l'abonné.

5. Remplissage du DLQ

Arrêter la publication non critique, activer batch-redrive avec un RPS bas, soulever les alertes aux propriétaires d'abonnements.


19) Erreurs typiques

Traitement lourd synchrone jusqu'à la réponse 2xx → retraits et doublons.
Il n'y a pas de signature corps/fenêtre temporelle → de vulnérabilité au remplacement/repliement.
L'absence de 'event _ id' et 'inbox' → ne peut pas être rendue idempotente.
La tentative de « l'ordre mondial » → les blocages éternels des files d'attente.
Retrai sans jitter/limites → amplification de l'incident (thundering herd).
Un pool commun unique pour tous les abonnés → « bruyant » met tout le monde.


20) Chèque-liste avant la vente

  • Contrat : 'event _ id', 'partition _ key', 'seq', 'event _ type. vN', signature HMAC et timestamp.
  • Expéditeur : outbox, sérialisation par clé, retraits avec backoff + jitter, TTL, DLQ et redrive.
  • Destinataire : entrée rapide dans inbox + 2xx ; traitement idempotent ; DLQ local.
  • Sécurité : TLS, signatures, anti-repli, dual-secret, rotation.
  • Quotas/limites : fair-queue per tenant/endpoint, respect « Retry-After ».
  • API reconcile et chekpoints ; documentation pour les abonnés.
  • Observabilité : p95/flux/erreurs/DLQ, trace par 'event _ id'.
  • La versionation des événements et la politique de l'évolution des schémas.
  • Pleybooks d'incidents et « bouton » de pause/décongélation globale.

Conclusion

Les webhooks fiables sont un protocole au-dessus de HTTP, pas seulement « POST with JSON ». Un contrat clair (ID, clé d'ordre, signature), une idempotence, des retraits avec jitter, une file d'attente juste et des playbacks bien réglés transforment le « meilleur cas » en un mécanisme de livraison prévisible et mesurable. Construisez at-least-once + ordre par clé + reconcile, et le système survivra calmement au réseau, aux pics de charge et aux erreurs humaines.

Contact

Prendre contact

Contactez-nous pour toute question ou demande d’assistance.Nous sommes toujours prêts à vous aider !

Commencer l’intégration

L’Email est obligatoire. Telegram ou WhatsApp — optionnels.

Votre nom optionnel
Email optionnel
Objet optionnel
Message optionnel
Telegram optionnel
@
Si vous indiquez Telegram — nous vous répondrons aussi là-bas.
WhatsApp optionnel
Format : +code pays et numéro (ex. +33XXXXXXXXX).

En cliquant sur ce bouton, vous acceptez le traitement de vos données.