À 1 h du matin du Black Friday de novembre 2024, l'OMS d'un 3PL transfrontalier de cosmétiques dans l'est de la Chine a commencé à lever des timeouts d'API en masse. Le premier réflexe de l'ingénieur d'astreinte a été d'ajouter des retries : renvoyer après un timeout de 5 secondes, jusqu'à 3 tentatives. À 3 h du matin, toute la chaîne s'était effondrée : le WMS n'obtenait plus les accusés de réception des commandes, le TMS ne pouvait plus consulter les factures de fret, et les statuts des tâches de picking restaient non reportés pendant 40 minutes. L'entrepôt est retombé sur la réconciliation manuelle. Ce n'était pas un incident isolé ; c'est un scénario récurrent dans les intégrations de systèmes d'entrepôt. Un timeout d'API, transformé par des retries bien intentionnés en tempête de retries.

Le phénomène : comment un timeout dégénère en effondrement en chaîne

La chronologie de cette nuit est instructive. Les ventes de minuit du Black Friday ont fait exploser le volume de commandes de l'OMS ; l'API d'admission des commandes du WMS a ralenti et des timeouts de 5 secondes sont apparus. La logique de retry du WMS était codée en dur : renvoyer immédiatement en cas de timeout, 3 tentatives. Mais la consultation des factures de fret du TMS subissait la même charge de pointe, et le trafic de retries du WMS a multiplié plusieurs fois le taux de requêtes vers le TMS. Le TMS a cédé et a martelé l'API de suivi du transporteur, déclenchant son limiteur de débit. Une fois limité, les callbacks se sont accumulés en file et chaque mise à jour de statut de picking du WMS s'est coincée — un timeout sur un maillon, amplifié saut par saut par les retries de chaque couche, jusqu'à faire tomber toute la chaîne.

La littérature publique de conception de systèmes permet de quantifier cette amplification. Supposons que la chaîne d'appels compte 4 sauts (OMS → WMS → TMS → API du transporteur) et que chaque saut réessaie deux fois en cas de timeout. Dans le pire des cas, le service le plus en aval fait face à 3 × 3 × 3 = 27 fois son volume normal de requêtes. Une API saine à 200 QPS se retrouve soudain face à 5,400 QPS — alors que les limites de débit des transporteurs sont généralement fixées à seulement 2–3× le pic normal. C'est un calcul illustratif, mais il explique pourquoi le TMS est tombé le premier cette nuit-là : il ne faisait pas face à « un peu plus » de trafic, mais à un écrasement d'un ordre de grandeur.

Un second cas mérite autant d'attention. Le TMS d'un 3PL appelait l'API de suivi d'un transporteur avec un timeout de 30 secondes et sans disjoncteur. En haute saison, les requêtes restaient suspendues sur des timeouts de 30 secondes, le pool de threads s'est rempli, et les callbacks de statut du WMS ne pouvaient plus obtenir un thread — en file pendant 40 minutes. La cause racine n'était pas vraiment le timeout ; c'est que les requêtes en timeout continuaient d'occuper des threads. Les longs timeouts blessent l'aval plus que les courts — une conclusion que beaucoup d'ingénieurs ont à l'envers.

Les chiffres : l'amplification des retries fait plus peur qu'il n'y paraît

Poussons le calcul un cran plus loin. Le pouvoir destructeur d'une tempête de retries vient de deux multiplicateurs qui se combinent : la profondeur — chaque saut supplémentaire multiplie l'amplification par un nouveau nombre de retries ; et la durée — plus le timeout est long, plus chaque requête suspendue retient des ressources, et plus la fenêtre de récupération de l'aval est courte. Selon l'analyse 2015 du blog AWS Architecture dans « Exponential Backoff And Jitter », les retries à rythme fixe cachent un autre tueur : la synchronisation. Chaque client expire au même moment et réessaie au même moment, résonnant en vagues — à peine l'aval reprend-il son souffle, la vague suivante arrive.

L'effondrement de cette nuit n'était donc pas « trop de trafic » mais « des retries trop synchronisés ». L'OMS, le WMS et le TMS utilisaient le même modèle — timeout de 5 secondes, 3 retries immédiats — battant en parfaite synchronisation, comme trois foules se pressant à une porte en même temps. C'est aussi pourquoi de nombreuses postmortems concluent « ajouter des serveurs » et voient peu d'amélioration : les serveurs ajoutent de la capacité, tandis que les tempêtes consomment des fenêtres de temps de récupération. Des dimensions différentes.

L'attribution : quatre mécanismes de retry, et pourquoi seul « backoff + jitter + disjoncteur » survit

Alignées côte à côte, les stratégies de retry courantes racontent une histoire claire :

Stratégie Mécanisme Amplification Défaut fatal
Retry immédiat Renvoyer aussitôt, jusqu'à N fois N×, croît avec la durée de la panne La seconde vague arrive avant que l'aval ne récupère
Retry à intervalle fixe Renvoyer toutes les T secondes N×, décalage limité Tous les clients réessaient en phase — résonance
Backoff exponentiel Les attentes croissent 2s → 4s → 8s Décroît avec le temps, donne du répit Ne corrige pas la synchronisation des retries
Backoff + jitter Backoff plus jitter aléatoire Décroît et désynchronise Un peu plus délicat à bien implémenter
Disjoncteur + fallback S'ouvre au-delà d'un seuil de taux d'échec, sondes half-open Quasi nulle Exige un chemin de fallback conçu

La valeur du backoff est « de plus en plus lent », achetant du temps de récupération ; la valeur du jitter est de briser la synchronisation — le vrai carburant d'une tempête de retries n'est pas le fait de réessayer, mais que chaque client réessaie dans la même seconde. Le disjoncteur, un pattern introduit par Michael Nygard dans Release It!, ouvre le circuit passé un seuil de taux d'échec, cesse d'envoyer des requêtes, et fait des sondes half-open avant de laisser repasser le trafic. Pour les intégrations WMS-transporteur, c'est presque obligatoire : marteler une API de transporteur limitée ne vous vaut qu'une place sur sa liste de blocage.

Une règle de plus, sous-estimée : seuls les endpoints idempotents méritent des retries. Les opérations d'écriture comme la passation de commande ou la déduction de stock, réessayées sans clé d'idempotence, peuvent devenir des commandes en double et des déductions en double — bien plus coûteuses qu'un timeout. Beaucoup de docs d'intégration WMS/OMS écrivent nonchalamment « réessayer 3 fois » sans jamais répondre à « et si la commande passe deux fois ? ».

En pratique : trois règles pour les intégrations de systèmes d'entrepôt

Premièrement, étagez vos timeouts. Les requêtes de périphérie reçoivent 3 secondes, les API centrales de commandes 10 secondes, et les grosses réconciliations par lots évitent entièrement le HTTP synchrone au profit de files asynchrones. Les timeouts plus longs ne sont pas plus cléments — ils retiennent les ressources plus longtemps.

Deuxièmement, écrivez la politique de retry dans le document d'intégration, pas dans les valeurs par défaut du code. Base du backoff, plage de jitter, tentatives maximales, seuils du disjoncteur — quatre chiffres à aligner avec l'amont et l'aval pendant les tests d'intégration. L'effondrement de cette nuit-là est arrivé, directement, parce que trois couches partageaient une configuration modèle et que personne n'avait considéré la résonance.

Troisièmement, limitez en aval et isolez les bulkheads. La consultation des factures de fret du TMS et les callbacks de statut du WMS ne devraient pas partager un pool de threads ; l'un saturé ne doit pas tuer l'autre. La limitation côté client sur les API externes des transporteurs compte aussi — leur limite de débit les protège eux ; la vôtre vous protège vous.

Un jugement contre-intuitif mérite d'être souligné : après un timeout, « attendre plus longtemps avant de réessayer » est souvent pire que « échouer vite et laisser l'appelant mettre en file ». Les pools de threads meurent d'occupation concurrente, pas de nombre de retries. Une requête occupant un thread pendant 30 secondes blesse l'aval plus qu'un timeout de 3 secondes plus 2 retries. Timeouts courts, peu de retries, échec rapide remonté à l'appelant pour mise en file — en apparence une moins bonne UX, mais le choix le plus responsable pour toute la chaîne.

La tendance est claire : le retry migre de « responsabilité de l'appelant » vers « capacité de l'infrastructure ». Les files de lettres mortes (dead-letter queues), le pattern outbox et les service meshes poussent la politique de retry dans la couche d'infrastructure, et le code métier écrit de moins en moins de logique de retry à la main. C'est un progrès — une cause racine des tempêtes est que chaque équipe écrivait ses propres retries, des rythmes jamais alignés. Le jour où la logique de retry disparaîtra entièrement du code métier, les tempêtes seront vraiment domptées. D'ici là, la section « stratégie de retry » de votre doc d'intégration WMS mérite une réécriture — maintenant.

Par Dr. Chen, chercheur en supply chain

Traduit de l'anglais. En cas de divergence, la version anglaise fait foi.