Oyun Kitabı

Demande d'idempotence (transaction sécurisée répétable) au-delà de l'API (interface de programmation d'application) (Demande Didempotence Transaction Securisee Repetable Au Dela DE Lapi Interface DE Programmation Dapplication)

L'idempotence n'est pas un simple en-tête. Il s'agit d'une pile de défense qui doit être configurée séparément sur cinq couches différentes, de la clé API au pointeur d'étape.

Moteur de paiement distribué

Partie 5 de 22

Une série d'architectures de paiement distribuées qui comblent le fossé entre la capture et l'achèvement.

Distributed payment engine architecture diagram

L'idempotence est une pile, pas un en-tête

La plupart des équipes apprennent l'idempotence en « ajoutant un en-tête Idempotency-Key à la requête API » et la laissent là. Ce n’est que la pointe de l’iceberg des systèmes de paiement. Le même processus peut se « répéter » dans votre système à au moins cinq points différents : la nouvelle tentative du client, la nouvelle tentative du webhook de la PSP, la livraison au moins une fois de la file d'attente des messages, la récupération du travail du travailleur, la réexécution de l'étape de la saga.```text Client retry → API idempotency key PSP retry → Gateway event id Broker retry → Inbox kaydı Worker retry → Job uniqueness Saga retry → Step marker


## Concepts à la première mention```text
📦 API Idempotency Key
İstemcinin gönderdiği, aynı isteğin tekrar gönderilmesi halinde aynı sonucu garanti eden benzersiz anahtar.

📦 Gateway Event ID
PSP'nin her webhook veya bildirime verdiği benzersiz kimlik; aynı olayın birden fazla teslimatını ayırt etmeye yarar.

📦 Inbox
Gelen bir olayın işlenmeden önce kaydedildiği, tekrarları filtreleyen dayanıklı bir tablo.

📦 Job Uniqueness
Bir arka plan işinin (job) aynı iş anahtarıyla ikinci kez kuyruğa girmesini önleyen kısıt.

📦 Step Marker
Bir saga adımının tamamlandığını kalıcı olarak işaretleyen, yeniden çalışmayı önleyen kayıt.
```Ces cinq concepts ne sont pas interchangeables. La clé d'idempotence de l'API empêche la duplication entre vous et le client ; mais cela n'affecte pas du tout le webhook de votre PSP, la livraison de votre file d'attente ou le travail de votre travailleur.

## Couche 1 : requête API

Si le client appuie deux fois sur le bouton « Payer » (délai du réseau, double clic), le client envoie la demande avec le même `Idempotency-Key`. Si le serveur a vu cette clé, il ne relancera pas le processus ; Renvoie le résultat de la première exécution. Cette couche est entièrement un contrat entre votre API et le client.```text
POST /payments  Idempotency-Key: abc123
  → ilk çağrı: işlem çalışır, sonuç kaydedilir
  → aynı key ile ikinci çağrı: kayıtlı sonuç döner, işlem tekrar çalışmaz
```## Couche 2 : Événement de la PSP

La PSP peut envoyer le même événement (par exemple « capture réussie ») plusieurs fois en raison de problèmes de réseau ou de sa propre politique de nouvelle tentative. Chacun de ces événements possède un identifiant d'événement unique attribué par PSP. Si vous voyez cet identifiant, vous ne devez plus gérer l'événement, mais vous devez également informer clairement (ACK) la PSP que vous ne l'avez pas fait.```text
Webhook #1: event_id=evt_001, type=payment.captured
Webhook #2: event_id=evt_001, type=payment.captured  (tekrar teslim)
  → aynı event_id görülmüşse, işlem atlanır, 200 OK döner
```## Couche 3 : File d'attente des messages / Boîte de réception

Si la vérification de l'identifiant de l'événement est effectuée dans le code qui traite directement l'événement, vous courez le risque que le même événement soit traité par deux travailleurs différents dans une situation de concurrence critique. C'est pourquoi le modèle de boîte de réception est utilisé : l'événement est d'abord écrit dans la table de boîte de réception avec une contrainte unique ; Si cette écriture échoue (elle existe déjà), l'événement a déjà été vu et l'opération est ignorée en toute sécurité.```text
INSERT INTO inbox (event_id, ...) VALUES ('evt_001', ...)
  → başarılı: ilk kez görülüyor, işlem kuyruğuna eklenir
  → unique constraint hatası: zaten görülmüş, sessizce atlanır
```## Couche 4 : le travail lui-même

Après la boîte de réception, le travail est transféré à un travail en arrière-plan. Ce travail peut également être mis en file d'attente plusieurs fois de lui-même (par exemple, lors d'un mécanisme de nouvelle tentative ou d'un redéploiement). La file d'attente des tâches doit rejeter une deuxième tâche avec la même clé de tâche (par exemple `payment_id + step_name`).```text
Job key: payment_id=pay_42, step=finalize_stock
  → aynı key ile ikinci job denemesi: kuyruk seviyesinde reddedilir
```## Couche 5 : étape de la saga elle-même

Même pendant l'exécution du travail, l'étape elle-même doit être idempotente, car le travail lui-même peut redémarrer après un crash. Cette dernière couche est constituée de marqueurs d'étape, que nous avons introduits au chapitre trois : chaque étape marque de manière permanente son achèvement, et si l'étape est réexécutée, elle vérifie cette marque afin de ne pas faire à nouveau le vrai travail (déduire l'inventaire, ouvrir un dossier financier).```text
Step marker: finalize_stock=DONE (payment_id=pay_42)
  → adım tekrar çağrılırsa, marker kontrol edilir, iş tekrar yapılmaz
```## Pourquoi ces cinq couches sont-elles requises séparément

Chaque couche répond à une question différente « qui renvoie » : le client, le PSP, la file d'attente, le travailleur ou le travail lui-même. Si vous installez l'idempotence uniquement au niveau de la couche API et ignorez les quatre autres, votre système peut avoir une saga de finalisation exécutée "une fois dans l'API, mais trois fois en arrière-plan" - et vous ne remarquerez ce bug qu'en production, généralement avec une plainte client.

## Les confrontations les plus déroutantes de cet épisode```text
❌ Idempotency-Key header'ı eklemek, idempotency problemini çözer
✓ Bu header sadece istemci-API katmanındaki tekrarı çözer

❌ PSP event id kontrolü tek başına yeterlidir
✓ Event id kontrolü, race condition'a karşı bir inbox/unique constraint ile desteklenmelidir

❌ Job kuyruğu at-least-once teslimat yaparsa, iş otomatik olarak idempotent olur
✓ At-least-once teslimat + idempotent olmayan iş = güvenli değil; iş kendi başına idempotent olmalıdır

❌ Bir saga adımı başarıyla tamamlandıysa tekrar çağrılması zararsızdır
✓ Adım işaretçisi yoksa tekrar çağrı, yan etkiyi (stok düşme, ödeme) ikinci kez tetikler

Vérifiez votre pile d'idempotence

  1. Votre API possède-t-elle une clé d'idempotence ? Si oui, combien de temps conservez-vous le résultat ?
  2. Vérifiez-vous les identifiants d'événements sur vos webhooks PSP ou traitez-vous chaque webhook directement ?
  3. Avez-vous une contrainte unique pour l'identifiant d'événement dans votre table Boîte de réception, ou effectuez-vous la vérification dans le code de l'application (risque de condition de concurrence critique) ?
  4. Votre file d'attente de tâches rejette-t-elle une deuxième tâche avec la même clé de tâche ?
  5. Chaque étape de la saga recherche-t-elle un marqueur qui vérifie sa propre achèvement, ou refait-elle le travail à chaque exécution ?

Si deux de ces cinq couches sont manquantes, votre système est probablement sujet à des erreurs de double validation « rares mais récurrentes ».

Choses à retenir de cette section

  1. L’idempotence n’est pas un simple en-tête ou un seul contrôle ; Il s'agit d'une pile qui doit être installée séparément en au moins cinq couches indépendantes.
  2. Chaque couche répond à une source de relecture différente (client, PSP, file d'attente, travailleur, étape de la saga) ; l'un n'inclut pas l'autre.
  3. Le modèle de boîte de réception est une solution structurelle qui sécurise la vérification de l'identifiant de l'événement par rapport aux conditions de concurrence, il ne s'agit pas simplement d'une vérification « si ».
  4. Dans le modèle de livraison au moins une fois, une étape de travail non idempotente sera tôt ou tard exécutée deux fois.

Réduire l'idempotence à un en-tête, c'est comme mettre une seule porte dans un immeuble de cinq étages et laisser ouvertes les fenêtres des quatre autres étages.

FAQ

Frequently asked questions

Qu'est-ce que la clé d'idempotence de l'API ?

Une clé unique envoyée par le client qui garantit le même résultat si la même demande est renvoyée.

Qu’est-ce que l’ID d’événement de passerelle ?

L'identifiant unique que la PSP donne à chaque webhook ou notification ; Il sert à distinguer plusieurs diffusions d’un même événement.

Est-il vrai que « l'ajout de l'en-tête Idempotency-Key résout le problème d'idempotence » ?

Cet en-tête résout uniquement la répétition au niveau de la couche client-API

Que corrige cette section ?

Cette section vous explique comment configurer l'idempotence à chacune de ces cinq couches séparément, plutôt qu'en un seul point. L’idempotence n’est pas un seul en-tête ou un seul contrôle ; Il s'agit d'une pile qui doit être installée séparément en au moins cinq couches indépendantes. La plupart des équipes apprennent l'idempotence en « ajoutant un en-tête `Idempotency-Key` à la requête API » et la laissent là. Ce n’est que la pointe de l’iceberg des systèmes de paiement. Le même processus peut se « répéter » dans votre système à au moins cinq points différents : la nouvelle tentative du client, la nouvelle tentative du webhook de la PSP, la livraison au moins une fois de la file d'attente des messages, la récupération du travail du travailleur, la réexécution de l'étape de la saga.

Principes d'ingénierie appris

  • L'idempotence n'est pas un simple en-tête ; Il s'agit d'une pile qui doit être configurée séparément au niveau des étapes API, passerelle, boîte de réception, tâche et saga.
  • Chaque couche répond à une source de répétition différente ; En installer un et ignorer les autres laisse le système semi-protégé.
  • Dans le modèle de livraison au moins une fois, une étape non idempotente est vouée à s'exécuter deux fois, tôt ou tard.

Continuer la lecture

Continuer la lecture

Suivant en série

Suivant en série

Même série

Paylaş