Pourquoi une intégration fonctionne en démonstration mais échoue silencieusement en production

Lors d'un test d'acceptation standard, on envoie un seul message, on constate qu'il est bien arrivé, et on le valide. En production, cette même intégration traite des milliers de messages par jour, et certains échoueront – à cause d'un délai d'attente (timeout), d'un verrouillage de ligne, d'une autorisation expirée ou d'un changement de schéma dans le système secondaire. La question qui définit la qualité de la solution n'est pas "L'intégration fonctionne-t-elle ?", mais plutôt "Que se passe-t-il quand elle ne fonctionne pas, et qui s'en aperçoit ?".

La plupart des défaillances coûteuses que j'ai observées ne provenaient pas d'un bug dans le code de l'intégration elle-même, mais de l'absence de trois capacités : l'identification qu'un message a échoué, un mécanisme qui réessaie sans créer de doublons, et un processus qui s'assure que les informations dans les deux systèmes sont réellement cohérentes en fin de journée. Sans cela, toute intégration "fonctionne" jusqu'au moment où l'on découvre qu'elle n'a pas fonctionné depuis deux semaines.

Les quatre couches d'une gestion d'erreurs efficace

CoucheProblème résoluÉchec typique sans cette couche
IdempotenceLa réexécution du même message ne crée pas de doublonCommande ou mouvement de stock en double après un réessai
Réessai avec BackoffL'échec temporaire (Timeout, Limite de Taux) est corrigé automatiquementUne charge momentanée se transforme en panne permanente
Dead Letter QueueUn échec non temporaire est signalé et ne disparaît pas silencieusementUn message est "avalé" et les parties pensent qu'il a été traité
Réconciliation métierLes écarts de données qui n'ont pas échoué clairement sont détectésUn rapport mensuel révèle un écart dont l'origine est difficile à retracer

Chaque couche dépend de la précédente. Un réessai sans idempotence crée des doublons ; une file de messages morts (Dead Letter Queue) sans réconciliation masque le fait que même les messages "techniquement" réussis n'ont pas nécessairement reflété la situation métier correcte.

Idempotence : La clé pour prévenir les doublons

Toute intégration capable de recevoir le même message plus d'une fois – et presque toutes les intégrations le sont – nécessite une clé unique externe (External ID) qui identifie l'événement, et pas seulement l'enregistrement. Dans Salesforce, l'implémentation courante est un Upsert basé sur un champ External ID avec une contrainte Unique, combinée à une table de log (Custom Object ou Platform Event Log) qui enregistre quels identifiants d'événements ont déjà été entièrement traités.

L'erreur fréquente : se contenter d'un Upsert sur l'enregistrement métier lui-même (par exemple l'External ID de commande) sans documenter les étapes intermédiaires. Si le processus inclut également une mise à jour de stock dans un système externe, un Upsert sur la commande n'empêche pas un appel en double pour la mise à jour du stock – chaque sous-opération ayant un effet secondaire externe (Side Effect) doit être idempotente en soi, pas seulement l'enregistrement final.

Réessai : Politique de Backoff et classification des erreurs

Toutes les erreurs ne méritent pas un réessai. Il convient de distinguer trois catégories :

  • Erreurs temporaires (Timeout, 503, Limite de Taux) – Candidats au réessai avec "Exponential Backoff", c'est-à-dire que l'intervalle entre les tentatives augmente (par exemple 30 sec, 2 min, 10 min) afin de ne pas aggraver la charge.
  • Erreurs structurelles (champ obligatoire manquant, violation de règle de validation, valeur invalide) – Ne feront pas l'objet d'un réessai, car elles échoueront de la même manière. Elles doivent passer directement dans la Dead Letter Queue.
  • Erreurs d'autorisation ou de configuration (jeton expiré, changement de version d'API) – Nécessitent une alerte immédiate à l'équipe technique, car elles bloquent toute la file d'attente et pas seulement un message individuel.

Dans Salesforce, l'implémentation du réessai se fait généralement au niveau du middleware ou dans les processus Apex Queueable/Batch avec un compteur de tentatives conservé sur l'enregistrement lui-même. Un nombre de tentatives raisonnable pour la plupart des cas est de 3 à 5 avec Backoff, et non un réessai infini – un réessai illimité transforme une panne temporaire en une charge continue sur les deux systèmes.

Dead Letter Queue : Où "vivent" les messages échoués

Une Dead Letter Queue n'est pas seulement un lieu de stockage – c'est un contrat. Chaque message qui y arrive doit contenir : l'identifiant original de l'événement, le Payload complet, une cause d'échec classifiée, le nombre de tentatives effectuées, et l'heure d'entrée dans la file. Sans ces informations, le "traitement" de la Dead Letter Queue relève de la conjecture.

Deux approches courantes pour l'implémentation dans Salesforce :

  1. Un objet personnalisé dédié (Integration_Failed_Message__c) avec des champs structurés et des vues de liste (List View) par type d'erreur – convient lorsque la transparence est nécessaire pour l'équipe métier au sein de Salesforce.
  2. Une file externe au niveau du middleware (par exemple, Dead Letter Exchange dans MuleSoft/Boomi) – convient lorsque l'équipe technique surveille en dehors de Salesforce et souhaite éviter de surcharger l'Org.

Le choix dépend de celui qui est censé agir sur l'échec : si c'est un propriétaire de processus métier, il doit le voir dans Salesforce ; si c'est une équipe d'intégration technique, il est préférable de le faire au niveau externe.

Réconciliation métier : Le contrôle qui révèle ce que les réessais n'ont pas intercepté

Même avec une idempotence et des réessais parfaits, il existe des échecs qui "réussissent" techniquement mais créent un écart métier – par exemple, un message reçu et traité, mais avec une valeur incorrecte provenant d'une source de données obsolète. La réconciliation est un processus périodique (quotidien, horaire, selon la fréquence des événements) qui compare un nombre ou une somme cumulée entre les deux systèmes – par exemple, le nombre de commandes créées dans l'ERP par rapport au nombre de commandes créées dans Salesforce pour la même journée – et met en évidence les écarts avant qu'ils ne se transforment en incident client.

Un processus de réconciliation efficace n'exige pas une vérification champ par champ de chaque enregistrement ; une somme de contrôle (checksum) ou un décompte cumulé suffit pour signaler quand il est nécessaire de descendre au détail. Dans la plupart des organisations, une fréquence quotidienne est suffisante ; pour les processus financiers ou critiques (commandes, facturations), une vérification dans les heures est requise.

Cadre de décision : Quand chaque couche est obligatoire et quand on peut s'en passer

CritèreIdempotence obligatoireRéessai automatique obligatoireDead Letter Queue distincte obligatoireRéconciliation quotidienne obligatoire
L'événement génère une transaction financière ou de stockOuiOuiOuiOui
L'événement est unidirectionnel, lecture seule (Read)Non critiqueOuiNonNon
Volume supérieur à 500 messages par jourOuiOuiOuiRecommandé
Partenaire externe sans SLA de haute disponibilitéOuiOui, avec Long BackoffOuiRecommandé
Intégration entre deux objets non financiers à faible volumeRecommandéRecommandéNon nécessaireNon

La règle qui guide ce tableau : plus un échec a une implication financière ou irréversible (expédition, facturation, mise à jour de stock), plus les quatre couches passent de "souhaitable" à "obligatoire" – quel que soit le volume.

Scénario d'exemple : Un détaillant avec synchronisation de commandes bidirectionnelle

Une entreprise de vente au détail avec 40 succursales utilise Salesforce pour la gestion des commandes B2B et un ERP externe pour l'inventaire et la facturation. L'intégration a été initialement construite avec un simple appel REST : lorsqu'une commande est créée dans Salesforce, un appel synchrone la crée dans l'ERP. Sans réessai, sans Dead Letter Queue.

Pendant une période de forte activité (Black Friday), l'ERP a commencé à renvoyer des erreurs de délai d'attente (Timeout) pour environ 3 % des appels. Sans mécanisme de réessai, ces 3 % ont simplement "disparu" – la commande est restée dans Salesforce avec le statut " Envoyée " sans que l'ERP n'en ait connaissance. En deux jours, environ 140 commandes se sont accumulées sans entrer dans le processus d'emballage, et n'ont été découvertes que lorsque des clients ont appelé pour s'informer de la marchandise.

La solution mise en place par la suite : une couche Queueable en Apex qui réessaie jusqu'à 5 fois avec un Backoff de 1/5/15/30/60 minutes ; un champ ERP_Sync_Status__c avec les valeurs Pending/Synced/Failed ; un Custom Object Integration_Failed_Message__c qui centralise les échecs finaux avec un bouton "Retraiter" pour l'équipe opérationnelle ; et un rapport de Réconciliation quotidien qui compare le nombre de commandes entre les systèmes et envoie une alerte Slack lorsque l'écart dépasse zéro. Le temps de détection d'une défaillance similaire est passé de deux jours à moins d'une heure.

Risques courants et actions préventives

RisqueComment il se manifesteAction préventive
Réessai infini sur une erreur structurelleLe même message échoue à maintes reprises et génère une surchargeClasser les erreurs à l'avance et envoyer les erreurs structurelles directement à la Dead Letter Queue
Absence de clé unique pour l'événementUn réessai ou un appel en double crée un enregistrement en doubleExternal ID sur l'événement, pas seulement sur l'enregistrement final
Dead Letter Queue sans propriétaireLes messages s'accumulent et personne ne les clôtureDéfinir un propriétaire et un SLA de traitement par type d'événement, non par système
Surveillance technique uniquement (statut API)L'intégration est "verte" mais les données métier ne sont pas cohérentesAjouter une réconciliation qui compare le résultat métier, pas seulement le code de réponse
Backoff fixe et trop courtLes tentatives répétées aggravent la charge lors d'une panne généraliséeExponential Backoff avec un plafond de tentatives défini

Checklist avant d'approuver la conception de la gestion des erreurs

  • ☐ Chaque événement possède une clé unique (External ID) pour éviter les doublons lors des réexécutions.
  • ☐ Les erreurs sont classifiées à l'avance comme temporaires/structurelles/d'autorisation, avec un traitement distinct pour chaque type.
  • ☐ Une politique de Backoff est définie avec un nombre maximal de tentatives.
  • ☐ Une Dead Letter Queue est accessible avec le Payload complet et la cause de l'échec.
  • ☐ Un propriétaire et des SLA de traitement sont définis pour chaque type d'échec.
  • ☐ Un processus de réconciliation périodique compare les résultats métier entre les systèmes.
  • ☐ Les alertes arrivent sur un canal réellement consulté (pas seulement un log).
  • ☐ Le scénario de test inclut l'interruption du service du système secondaire, pas seulement le "Happy Path".

Comment cela s'intègre au reste de l'architecture

La conception de la gestion des erreurs ne se suffit pas à elle-même – elle repose sur la couche de données et les autorisations définies dans le Guide d'architecture CRM, et sur la décision d'implémenter la logique en Flow ou en Apex selon Salesforce Flow ou Apex. Le modèle d'autorisations par lequel les composants d'intégration écrivent les données doit être vérifié par rapport au Modèle d'autorisations de Salesforce, afin qu'un utilisateur technique de l'intégration n'obtienne pas un accès trop large. Et lorsque le volume de messages augmente, la question du réessai rencontre directement les limites des API détaillées dans Limites et Résilience des API Salesforce.

Résumé

La gestion des erreurs d'intégration n'est pas une fonctionnalité que l'on ajoute à la fin – c'est la différence entre un système qui se révèle défectueux après qu'un client s'est plaint, et un système qui s'alerte lui-même avant que les dommages ne s'accumulent. Les quatre couches – Idempotence, réessayage classifié, Dead Letter Queue avec propriétaire, et réconciliation métier – ne nécessitent pas un projet distinct, mais une décision explicite au stade de la planification, avant que la première intégration ne soit mise en production. Une organisation qui s'avertit elle-même de 3 % de messages échoués en moins d'une heure est fondamentalement différente d'une organisation qui le découvre par un client mécontent.