Lundi matin, l’export s’ouvre en double. Deux en-têtes, des lignes qui se répètent, des totaux incohérents. Les règles métier n’ont pas changé. Un traitement n’avait pas achevé son écriture que le suivant travaillait déjà au même endroit. Les journaux enregistrent deux exécutions réussies.
L’absence d’alerte induit en erreur : tant que l’on cherche un défaut de calcul, on perd du temps. Le calcul était exact. Il a été produit deux fois. En maintenance, la première question, avant d’optimiser une requête, est de savoir si deux instances peuvent s’exécuter ensemble.
Manifestation en production
Le premier traitement lit un lot, agrège, écrit un cliché ou un CSV. Il dépasse l’intervalle prévu : volume, API tierce lente, ou simplement un lundi plus chargé qu’un mercredi de recette. Le planificateur n’attend pas la fin. Il lance une seconde instance.
À partir de là, les résultats sont cohérents et faux. Deux totaux, deux fichiers, deux fois les mêmes appels sortants. Le métier constate un écart qu’il croit aléatoire. Relancer le traitement aggrave le chevauchement.
Sur le même existant, le processus pouvait aussi s’arrêter (mémoire, délai dépassé) sans ligne de journal exploitable. L’occurrence suivante partait sur un état à moitié écrit. Même famille : pas d’exclusion, pas de fin explicite. C’est le prolongement de la fiabilité des tâches asynchrones : une file sans motif d’arrêt se pilote à l’aveugle.
Un CSV qui s’allonge n’est souvent pas une fuite mémoire. C’est un fichier ouvert en ajout par deux processus, ou un export relancé avant la fin de l’écriture précédente. Les horodatages le montrent : deux en-têtes dans le même fichier, ou des plages de dates qui se recouvrent.
Un verrou partagé, pas un autre planning
Réduire la fréquence sans mesurer la durée réelle masque le problème tant que l’exécution tient dans l’intervalle, et le fait réapparaître dès qu’une journée dépasse. La correction consiste en un verrou partagé : si une instance détient encore la clé, la suivante s’arrête immédiatement, et l’événement est journalisé comme un report, non comme un succès.
La technique (verrou Redis, fichier, option du planificateur, mutex en base) importe moins que les règles suivantes :
- La clé est identique sur tous les processus et tous les serveurs, pas locale à une machine.
- La durée de vie du verrou dépasse le pire temps d’exécution observé, pas la moyenne de recette.
- Un arrêt brutal libère ou expire le verrou. Une durée infinie bloque la production.
- Les reports sont visibles : journal, métrique, alerte si trop de reports successifs.
On ne pose pas un verrou par précaution sur tous les traitements. Uniquement sur ceux qui ne doivent pas se recouvrir : agrégats, exports, synchronisations qui écrivent un cliché. Un travail réellement parallèle se découpe (lots, partitions) ; on ne le sérialise pas par crainte. En back-end, la distinction relève du contrat du traitement, pas du seul calendrier.
Points de contrôle
La revue est répétée sur chaque existant muni d’un planificateur.
- Durée réelle du traitement, pas celle indiquée en commentaire. Horodatages de début et de fin sur une semaine.
- Deux exécutions peuvent-elles écrire le même fichier, les mêmes lignes, le même cache ?
- Un arrêt (mémoire, interruption, déploiement) laisse-t-il une trace ?
- Le verrou, s’il existe, est-il visible de tous les serveurs ou seulement en local ?
Un verrou qui suffit en recette avec un seul processus échoue souvent en production à deux nœuds. L’essai utile consiste à lancer deux fois le traitement avec une pause artificielle, et à vérifier s’il y a une ou deux écritures.
Lorsque le traitement appelle une API métier, le chevauchement se paie aussi à l’extérieur : doubles créations, quotas, files côté partenaire. L’idempotence des appels ne remplace pas le verrou : le verrou évite le recouvrement ; l’idempotence limite les dégâts s’il survient malgré tout.
Limites
On ne documente pas l’incident avec un nom de client ou un produit interne. Le motif suffit : un traitement qui se recouvre, un export qui s’allonge, un processus arrêté sans journal. On ne « corrige » pas en interrompant le processus chaque matin. On n’accélère pas l’intervalle : cela augmente le recouvrement. On n’ajoute pas une pause fixe en début de traitement en croyant synchroniser les nœuds.
Un export ou une synchronisation qui double des lignes alors que le métier n’a pas bougé n’est souvent pas un défaut de donnée. Ce sont deux exécutions. Côté maintenance applicative, on ouvre ce point avant d’optimiser le reste. Disponibilité mission dès septembre 2026. Le cadre est décrit sur l’expertise Scott-E.
Sur des exports quotidiens, le calendrier peut indiquer 2 h du matin et l’exécution durer 40 minutes, jusqu’au jour où une jointure non indexée passe à 70 minutes. L’intervalle n’a pas changé ; le recouvrement apparaît sans déploiement. D’où l’intérêt de mesurer la durée. Un historique dans les journaux vaut mieux qu’une estimation non vérifiée.
Une fois le verrou en place, on vérifie le report : deux lancements, un succès et un report journalisé. Deux succès indiquent que le verrou n’est pas partagé. Un succès et une erreur indiquent que le second lancement ne gère pas le cas « verrou déjà pris ». Un report n’est pas une exception. C’est un cas prévu.
Commentaires 0
Soyez le premier à commenter cet article.
Laisser un commentaire