Comment puis-je empêcher les exécutions de flux de travail en double lorsqu’un webhook est déclenché plusieurs fois ?
Quel est le message d’erreur (le cas échéant) ?
Webhook Set HTTP Request Airtable Je suis conscient que Stripe réessaie les requêtes échouées, mais même les requêtes réussies semblent parfois arriver deux fois. Comment puis-je m’assurer que chaque événement n’est traité qu’une seule fois ?
Veuillez partager votre flux de travail
(Sélectionnez les nœuds sur votre canevas et utilisez les raccourcis clavier CMD+C/CTRL+C et CMD+V/CTRL+V pour copier et coller le flux de travail.)
Partagez la sortie renvoyée par le dernier nœud
J’utilise un nœud Webhook qui reçoit des événements de Stripe. Occasionnellement, le même événement est livré plus d’une fois, ce qui amène mon flux de travail à traiter les commandes en double
Informations sur votre configuration n8n
- Version n8n : 1.123
- Base de données (par défaut : SQLite) : PostgreSQL
- Paramètre n8n EXECUTIONS_PROCESS (par défaut : own, main) :
- Exécution de n8n via (Docker, npm, n8n cloud, application de bureau) :
- Système d’exploitation :
Salut @Fatoki_Alfred
Chaque événement Stripe contient un identifiant unique id (par exemple, evt_1Nabc...). Pour vous assurer que chaque événement n’est traité qu’une seule fois, vous devriez suivre ces identifiants dans une table « événements traités » dédiée dans votre base de données Postgres.
Bonjour @Fatoki_Alfred
n8n dispose d’un nœud Remove Duplicates intégré qui fait cela sans table personnalisée ni requête. Placez-le juste après le nœud Webhook et définissez Operation sur « Remove Items Processed in Previous Executions », Keep Items Where sur « Value Is New », et Value to Dedupe On sur l’identifiant d’événement Stripe :
{{ $json.body.id }}
n8n conserve l’historique des identifiants vus dans sa propre base de données Postgres, ce qui persiste lors des redémarrages, et toute livraison répétée est supprimée avant d’atteindre vos étapes de commande.
Pour compléter les réponses ci-dessus : le point qui s’échappe souvent est la condition de concurrence (race condition). Si Stripe livre le même evt_id en parallèle, deux workflows peuvent passer par la vérification de dédoublonnage AVANT que l’un d’eux n’enregistre l’id — et les deux continuent. Le nœud Remove Duplicates résout le cas sériel, mais n’est pas atomique sous concurrence.
Pour vraiment vous protéger, faites le dédoublonnage directement dans la base : créez la colonne avec une contrainte UNIQUE (ex. : stripe_event_id TEXT UNIQUE) et, juste après le Webhook, un nœud Postgres avec INSERT … ON CONFLICT (stripe_event_id) DO NOTHING RETURNING id. Si le RETURNING revient vide, c’est une relivraison dupliquée → arrêtez le flux là (un IF qui vérifie s’il y a une ligne retournée). La base garantit l’atomicité, donc même deux livraisons simultanées : une seule remporte l’INSERT.
Deux choses supplémentaires qui réduisent beaucoup le problème à la source : (1) répondez 200 à Stripe aussi vite que possible (utilisez le Webhook en mode Respond Immediately ou un nœud Respond to Webhook au début) — les timeouts font que Stripe réessaie et c’est là que naissent beaucoup de « doublons » ; et (2) traitez la commande seulement après que l’INSERT de contrôle soit passé. Ainsi l’id de l’événement est votre vraie clé d’idempotence, et la logique de commande ne s’exécute jamais deux fois.
Bonjour @Fatoki_Alfred
Stripe réessaie intentionnellement les livraisons de webhooks, donc les événements en double sont attendus. L’approche recommandée est de rendre votre flux de travail idempotent au lieu de supposer que chaque webhook est unique.
La solution la plus simple est de stocker l’event.id de Stripe avant le traitement. Au début du flux de travail :
- Extrayez event.id.
- Interrogez votre base de données (ou Data Store) pour cet ID.
S’il existe déjà, arrêtez le flux de travail.
Sinon, enregistrez l’ID et continuez le traitement.
Utiliser un nœud IF avant votre logique métier est généralement suffisant.
Si vous écrivez dans Airtable ou une autre base de données, envisagez de rendre event.id un champ unique afin que les doublons soient automatiquement rejetés.
Traitez les webhooks Stripe comme une livraison au moins une fois et rendez le flux de travail idempotent. Utilisez l’ID d’événement Stripe comme clé d’idempotence. Au début du flux de travail, vérifiez la signature du webhook et tentez d’insérer cet ID d’événement dans une table PostgreSQL avec une contrainte d’unicité. Continuez uniquement si l’insertion réussit. Si l’ID existe déjà, retournez une réponse réussie et arrêtez sans créer à nouveau la commande.
Une table simple peut contenir event_id comme clé primaire plus status, received_at et completed_at. Dans le nœud Postgres, utilisez une insertion avec ON CONFLICT DO NOTHING et retournez si une ligne a été insérée. Envoyez ce résultat à un nœud IF. La branche true traite la commande et la branche false se termine. La contrainte de base de données est importante car deux copies peuvent arriver suffisamment près pour qu’une vérification lookup-then-insert séparée en laisse passer les deux.
Marquez l’enregistrement comme étant en cours de traitement quand il est revendiqué et complété uniquement après le succès de la commande. Décidez comment les enregistrements défaillants doivent être relancés afin qu’une erreur temporaire ne supprime pas définitivement l’événement. Transmettez également l’ID d’événement Stripe aux systèmes en aval en tant que leur clé d’idempotence si elle est prise en charge. Ne dédupliquezpas par client, montant ou horodatage car des paiements légitimes distincts peuvent partager ces valeurs.
Créez une clé d’idempotence à partir d’un identifiant d’événement stable et stockez-la avant l’exécution des nœuds coûteux. Si la même clé arrive à nouveau, retournez rapidement et définissez une expiration qui correspond à la durée pendant laquelle l’expéditeur peut réessayer.