Développement

Traitements asynchrones : décider ce qui doit pouvoir être rejoué

Comment concevoir un traitement asynchrone fiable, rejouable et exploitable : idempotence, états, relance, reprise manuelle et checklist avant production.

Par La rédaction DEV N SI ·

Illustration de l’article : Traitements asynchrones : décider ce qui doit pouvoir être rejoué

Le traitement avait été déplacé hors de l’écran pour accélérer l’expérience utilisateur. Sur le papier, tout allait mieux : le formulaire répondait vite, la file absorbait les pics et l’équipe pouvait lancer les exports sans bloquer l’application principale. Puis un mardi matin, plusieurs commandes sont restées dans un état intermédiaire. Certaines avaient été facturées, d’autres non. Un relancement manuel a corrigé une partie du problème, mais a aussi créé des doublons. !Infographie du circuit d’un message rejouable dans un traitement asynchrone. Le sujet n’était pas seulement technique. L’équipe avait bien créé un traitement asynchrone. Elle n’avait pas encore décidé ce qui devait être rejouable, observable, annulable ou bloquant. C’est cette décision qu’il faut prendre avant que la file, le batch ou le worker ne devienne une zone grise du système d’information.

Commencer par la question métier

Un traitement asynchrone fiable ne commence pas par le choix d’un broker, d’un ordonnanceur ou d’un service managé. Il commence par une question simple : que se passe-t-il si cette action échoue après avoir partiellement avancé ?

Envoyer une notification, recalculer un indicateur, synchroniser un dossier client, générer une facture ou clôturer une demande ne portent pas le même risque. Certains traitements peuvent être relancés sans conséquence visible. D’autres modifient des droits, déclenchent un paiement, écrivent dans plusieurs systèmes ou produisent une preuve attendue par un utilisateur.

Le premier tri consiste donc à séparer les traitements de confort, les traitements de continuité et les traitements engageants. Plus l’action crée un effet difficile à corriger, plus elle doit être conçue avec des garde-fous explicites.

Arbre de décision : faut-il rendre le traitement rejouable ?

Le raisonnement peut être tenu comme une suite de questions courtes. Si l’une d’elles reçoit une réponse incertaine, il vaut mieux documenter l’hypothèse et traiter le cas comme risqué.

  • Le traitement modifie-t-il une donnée métier durable ? Si oui, il doit laisser une trace exploitable et prévoir une reprise contrôlée.
  • Le traitement appelle-t-il un système externe ? Si oui, il doit gérer l’absence de réponse, la réponse tardive et le risque de double appel.
  • Le traitement peut-il être lancé deux fois avec le même message ? Si non, une clé d’idempotence ou une règle anti-doublon est nécessaire.
  • Une erreur peut-elle être corrigée par un utilisateur métier ? Si oui, l’état doit être compréhensible hors de l’équipe technique.
  • Le délai d’exécution a-t-il un impact sur l’activité ? Si oui, il faut une alerte orientée service, pas seulement une erreur dans les logs.

Cet arbre ne remplace pas l’analyse détaillée. Il évite surtout de traiter tous les traitements en arrière-plan comme de simples tâches techniques.

Choisir entre relance, compensation et abandon

Lorsqu’un traitement échoue, trois réponses reviennent souvent : relancer, compenser ou abandonner proprement. La mauvaise décision consiste à relancer mécaniquement sans savoir si l’action précédente a déjà produit un effet.

| Situation | Réponse à privilégier | Point de vigilance | | --- | --- | --- | | Calcul interne sans effet externe | Relance automatique limitée | Éviter les boucles infinies et conserver la dernière erreur lisible | | Écriture métier unique | Idempotence par identifiant fonctionnel | Définir ce qui fait foi en cas de doublon apparent | | Appel à un outil tiers | Vérification d’état avant nouvelle tentative | Ne pas supposer qu’une absence de réponse signifie un échec | | Action engageante ou coûteuse | File d’attente d’erreur et reprise manuelle | Donner assez de contexte pour décider sans fouiller le code | | Étape devenue invalide | Abandon explicite avec motif | Rendre l’état visible au support ou au métier concerné |

Ce tableau force une discipline utile : chaque erreur attendue doit mener vers une stratégie connue. Une exception non classée peut exister, mais elle ne doit pas devenir le mode normal d’exploitation.

Rendre l’idempotence compréhensible

L’idempotence est souvent présentée comme une propriété technique. Sur un projet métier, elle doit d’abord être exprimée en langage de processus : deux demandes identiques doivent-elles produire un seul résultat, deux résultats, ou une erreur de doublon ?

Pour une génération de document, le bon comportement peut être de renvoyer le document déjà produit. Pour une notification, il peut être acceptable de ne pas renvoyer le message. Pour une opération financière, la règle doit être beaucoup plus stricte et validée avec les personnes responsables du processus.

La clé d’idempotence doit donc être stable et reliée au métier : numéro de demande, identifiant de commande, période de traitement, version de dossier. Une clé purement technique peut aider l’implémentation, mais elle ne suffit pas toujours à expliquer ce qui s’est passé.

Prévoir les états intermédiaires

Un traitement asynchrone ne devrait pas se résumer à deux états, succès ou échec. Entre les deux, il existe souvent des étapes utiles : reçu, validé, en attente d’un système externe, à relancer, bloqué, abandonné, terminé.

Ces états évitent les diagnostics contradictoires. Le support sait si le dossier est encore en cours. L’exploitation sait si une action est attendue. Le développeur peut relier l’état visible aux événements techniques. Ce travail rejoint directement la qualité de la journalisation applicative : sans événements nommés, la reprise repose sur des suppositions.

Il faut aussi éviter de multiplier les états pour tout prévoir. Un bon état doit aider quelqu’un à décider. S’il ne change aucune action possible, il peut rester dans les traces techniques plutôt que dans le modèle métier.

Infographie à produire : le circuit d’un message rejouable

L’infographie associée à l’article doit montrer un circuit simple : événement reçu, validation, exécution, écriture de l’état, tentative contrôlée, file d’erreur, reprise humaine puis clôture. L’objectif n’est pas d’illustrer une architecture idéale, mais de rendre visibles les points où une décision doit être prise.

Cette représentation aide à discuter avec les métiers et l’exploitation. Elle montre qu’un traitement en arrière-plan n’est pas un trou noir : il a des entrées, des états, des limites et des sorties observables.

Organiser la reprise avant l’incident

La reprise ne doit pas dépendre d’une requête improvisée en base de données. Avant la mise en production, l’équipe doit savoir qui peut relancer, sur quel périmètre, avec quel contrôle et dans quel ordre. Pour les traitements sensibles, une reprise massive doit être séparée d’une reprise unitaire.

Un runbook court peut suffire : symptôme observable, vérifications, actions autorisées, critères d’arrêt et personne à contacter. Ce niveau de préparation complète naturellement un runbook d’incident, mais avec une granularité centrée sur le traitement lui-même.

La règle la plus utile reste simple : une action de reprise doit être plus sûre que l’erreur qu’elle tente de corriger. Si le relancement peut aggraver la situation, il doit être précédé d’une vérification ou d’une validation humaine.

Checklist avant mise en production

  • Le traitement possède un propriétaire fonctionnel et un propriétaire technique.
  • Les effets métier du traitement sont décrits, y compris en cas d’échec partiel.
  • Les messages ou demandes disposent d’un identifiant stable pour éviter les doublons.
  • Les erreurs attendues sont classées : relance, attente, reprise manuelle ou abandon.
  • Les états visibles permettent au support de répondre sans interroger directement les développeurs.
  • Les logs contiennent assez de contexte pour enquêter sans exposer de données inutiles.
  • La file d’erreur ou l’équivalent opérationnel est surveillée.
  • La procédure de reprise a été testée sur un cas réaliste.
  • Les actions manuelles dangereuses sont limitées, tracées et réversibles quand c’est possible.

Relier le traitement au pilotage du projet

Les traitements asynchrones sont souvent ajoutés tard dans un projet, quand l’équipe découvre qu’une opération est trop longue pour rester dans le parcours utilisateur. Ce déplacement règle un problème de performance, mais il crée un nouveau contrat d’exploitation.

Il faut donc intégrer ces décisions aux critères d’acceptation. Une user story qui déclenche un traitement différé ne devrait pas être terminée tant que l’équipe ne sait pas comment suivre son avancement, reconnaître un doublon, traiter une erreur et expliquer l’état à l’utilisateur ou au support.

Le gain est concret : moins de relances hasardeuses, moins de tickets flous, moins de corrections directes en production. Le traitement devient une partie maîtrisée du système, pas une tâche cachée derrière une file.

Prochaine étape

Choisissez un traitement déjà en production, de préférence un traitement qui a déjà nécessité une intervention manuelle. Reconstituez son chemin complet : déclencheur, données d’entrée, effets produits, états, erreurs possibles, reprise. Si l’équipe ne sait pas répondre à une étape, ce n’est pas un échec documentaire. C’est le meilleur endroit pour commencer à rendre le traitement rejouable.

Architecture · Exploitation · Projet · Qualité logicielle · Traitements asynchrones