← Tous les articles

Architecture · Systèmes distribués

Concevoir des traitements asynchrones qui résistent aux erreurs et aux redémarrages

Files de tâches, idempotence, reprises et observabilité : les fondations d’un travail long qui peut échouer sans perdre son état.

Concevoir des traitements asynchrones qui résistent aux erreurs et aux redémarrages

Une exportation volumineuse, une analyse documentaire ou une génération de média ne devrait pas immobiliser une requête HTTP pendant plusieurs minutes. Déplacer le travail dans une file améliore la disponibilité, mais ne garantit pas sa fiabilité. Le processus peut redémarrer après avoir effectué l’action sans avoir enregistré son succès, le réseau peut couper au mauvais moment et un message peut être livré plusieurs fois. La robustesse vient donc d’un modèle d’état explicite et d’opérations capables d’être rejouées sans produire de dégâts.

01

Reconnaître le moment de sortir du synchrone

Une requête synchrone convient lorsque la durée est courte, prévisible et liée à l’expérience immédiate. Elle devient fragile lorsque le travail dépend de plusieurs services, traite un grand volume ou doit continuer après la fermeture de l’interface. Augmenter le délai d’attente masque alors le problème sans le résoudre.

L’asynchrone sépare l’acceptation de la demande de son exécution. L’API crée un travail durable, retourne un identifiant et expose son état. L’utilisateur peut quitter la page, revenir plus tard ou recevoir une notification. Cette séparation impose toutefois de définir ce que signifie accepter, commencer, réussir, échouer ou annuler.

02

Modéliser le travail comme une machine d’état

Un simple booléen terminé ne suffit pas. Les états typiques sont en attente, en cours, réussi, échoué de manière récupérable, échoué définitivement et annulé. Chaque transition enregistre sa date, sa cause et la version du code qui l’a produite.

La progression doit refléter des étapes réelles plutôt qu’un pourcentage inventé. Télécharger, extraire, analyser, assembler et publier constituent des jalons observables. Si le traitement reprend, il peut repartir du dernier jalon validé au lieu de recommencer aveuglément.

  • Utiliser un identifiant stable pour chaque travail.
  • Conserver la cause et la catégorie des échecs.
  • Rendre les transitions atomiques lorsque c’est possible.
03

Rendre les effets idempotents

Une opération idempotente peut être répétée avec la même clé sans multiplier son effet. La création d’une facture, l’envoi d’une commande ou l’écriture d’un fichier doit associer la demande métier à une clé stable. Avant d’agir, le worker vérifie si cette étape a déjà produit un résultat.

L’idempotence ne signifie pas ignorer toutes les répétitions. Les paramètres associés à une clé doivent être comparés ; une même clé utilisée pour deux demandes différentes doit être refusée. Pour les systèmes externes, on stocke l’identifiant distant et le résultat reçu afin de réconcilier une réponse perdue.

04

Reprendre uniquement ce qui peut réussir plus tard

Une coupure réseau, une limitation temporaire ou un service indisponible peuvent justifier une reprise. Une entrée invalide, une permission refusée ou un format non supporté ne deviendront pas corrects après dix tentatives. Classer les erreurs évite de transformer une défaillance permanente en surcharge.

Les reprises utilisent un délai croissant et une part d’aléatoire afin que des milliers de workers ne recommencent pas au même instant. Elles restent plafonnées par un nombre de tentatives et une durée totale. Une fois la limite atteinte, le travail passe dans un état explicite et peut rejoindre une file de diagnostic.

  • Distinguer erreurs temporaires et permanentes.
  • Utiliser un backoff avec jitter.
  • Plafonner tentatives, durée et consommation.
05

Définir la responsabilité de la file et du worker

La file garantit généralement une livraison au moins une fois, pas une exécution exactement une fois. Le worker accuse réception seulement après avoir enregistré le résultat nécessaire à la reprise. Un délai de visibilité trop court peut provoquer une seconde exécution alors que la première travaille encore ; un délai trop long ralentit la récupération après un crash.

Les tâches doivent être assez petites pour être reprises, mais pas au point de créer des milliers de messages sans valeur métier. Le découpage suit les frontières de cohérence : une étape possède une entrée durable, un effet identifiable et une sortie réutilisable par la suivante.

06

Rendre chaque travail observable

Les logs utilisent l’identifiant du travail, de la tentative et de la corrélation métier. Les métriques suivent l’âge du plus ancien message, le temps d’attente, la durée d’exécution, les reprises, les échecs définitifs et la saturation des workers. Une file presque vide peut tout de même cacher un travail bloqué depuis plusieurs heures.

L’interface traduit ces états en messages utiles : demande reçue, analyse en cours, intervention nécessaire ou résultat disponible. Elle n’affiche pas une erreur technique brute et n’annonce pas une réussite avant que l’artefact final soit réellement accessible.

07

Tester les interruptions volontairement

Un test fiable arrête le worker après l’effet externe mais avant l’enregistrement local, livre deux fois le même message, expire un jeton et rend une dépendance indisponible. Il vérifie ensuite que le système reprend sans doublon et que l’état final reste explicable.

Le déploiement progressif conserve les anciens workers tant que les tâches de leur version existent. Les schémas de messages sont versionnés et compatibles pendant la transition. La question décisive n’est pas si le traitement échouera, mais si son état permettra de reprendre proprement lorsqu’il échouera.

  • Simuler un crash à chaque frontière d’effet.
  • Tester la livraison multiple d’un même message.
  • Prévoir l’annulation et la reprise manuelle.
  • Documenter la procédure de vidage ou de réconciliation.

Mettre en pratique

Des réalisations à consulter

Ces études de cas illustrent certains principes présentés dans ce guide. Elles complètent l’apprentissage sans exposer les choix internes ou le code des produits privés.

Étude de casNexus Worker MCP - Orchestration LLM FinOps

Serveur MCP agnostique qui délègue les tâches volumineuses à des modèles Worker économiques tout en laissant la supervision au modèle principal.

Étude de casDemo Studio - Moteur de Démonstrations Produit

Moteur local et multiplateforme pour capturer, narrer et rendre des démonstrations vidéo à partir d'interfaces web réelles.

Étude de casFinanceFlow Desktop

Application Windows autonome qui automatise le traitement de bons de commande, le rapprochement fournisseur et la préparation d'e-mails professionnels.

Références & prolongements

AWS Builders’ Library — Timeouts, retries and backoff with jitterStripe API — Idempotent requestsTemporal — Durable Execution