Aller au contenu principal

14 ter. Le temps, la concurrence et la cohérence : concevoir ce qui n'arrive pas dans l'ordre

Pourquoi ce chapitre existe

Une grande partie du code est écrite comme si les actions arrivaient une fois, dans l'ordre et sur une donnée immédiatement à jour. Les systèmes réels contredisent ces hypothèses : un message est rejoué, une requête est expirée puis réussit, deux personnes modifient la même ressource, l'horloge change de fuseau, un consommateur reçoit un événement en retard. Ces situations ne sont pas des cas exotiques ; elles sont le comportement normal des systèmes distribués et des produits qui vivent dans le temps.

Les idées essentielles

  • Le temps métier, le temps de traitement et le temps d'observation sont différents et doivent être nommés.
  • La concurrence est une décision de domaine : il faut choisir qui gagne, comment un conflit apparaît et ce qui peut être rejoué.
  • Les garanties d'ordre, d'unicité et de fraîcheur ne doivent jamais être supposées sans contrat.
  • Idempotence, version, horodatage, échéance et réconciliation sont des mécanismes complémentaires, pas des propriétés magiques.

Distinguer les temps qui comptent

Une commande peut être créée à 23 h 59 dans un fuseau, payée à minuit dans un autre, reçue par un entrepôt quelques secondes plus tard et comptabilisée le lendemain. Dire qu'elle a été « créée le 1er janvier » ne suffit pas tant que l'on ne sait pas pour quelle règle. Le temps d'effet métier, le moment où le système traite l'information et le moment où un utilisateur la voit peuvent légitimement différer.

QuestionTemps pertinentErreur fréquente
Quelle règle de prix s'applique ?Date d'effet métierUtiliser l'heure du traitement asynchrone
L'événement est-il en retard ?Heure de production et de réceptionDéduire l'ordre depuis l'heure d'arrivée
Le client peut-il annuler ?Échéance définie dans son contexteComparer des dates locales non normalisées
Une projection est-elle fraîche ?Âge de la dernière donnée appliquéeAfficher « à jour » sans mesure de délai

Concevoir les conflits au lieu de les masquer

Deux opérations concurrentes peuvent avoir des effets différents : changer une adresse et annuler un abonnement, réserver le dernier article, appliquer deux corrections financières. Une stratégie « dernier écrivain gagne » est parfois acceptable ; elle est dangereuse lorsqu'elle efface une décision importante sans signal. Le domaine doit choisir : rejet avec version attendue, fusion, priorité explicite, file séquentielle, compensation ou intervention humaine.

Le conflit n'est pas nécessairement un échec technique. Il peut être la manière correcte de demander à l'utilisateur ou au système de choisir entre deux intentions incompatibles.

Les événements arrivent rarement exactement une fois

Un producteur peut publier deux fois après un timeout ; un consommateur peut redémarrer après avoir traité sans avoir confirmé ; un message peut être retardé. Une clé d'idempotence permet de reconnaître qu'une intention ou un effet a déjà été traité. Elle doit être définie dans le vocabulaire métier : commandeId + type de décision est souvent plus robuste qu'un identifiant technique aléatoire généré à chaque retry.

L'idempotence ne résout pas tout. Elle ne réordonne pas des événements, ne choisit pas entre deux décisions concurrentes et ne répare pas une donnée manquante. Des versions, des règles de séquence, des délais de validité et des rapprochements restent nécessaires selon le contrat.

Ne jamais utiliser l'heure locale comme identifiant d'ordre global

Les horloges dérivent, les fuseaux changent et deux événements peuvent partager la même précision. L'heure est une information de contexte ; un ordre garanti doit être fourni par un mécanisme qui le promet réellement, ou ne pas être requis par la conception.

Anti-patterns

Traiter un retry comme une nouvelle intention

Un utilisateur qui réessaie après un écran figé ne demande pas nécessairement deux paiements. La frontière doit distinguer la répétition d'une même demande d'une action distincte, puis rendre ce comportement observable.

Cacher la cohérence éventuelle

Une projection peut être légèrement en retard sans être incorrecte. Le danger vient de la présenter comme immédiatement vraie, ou de laisser une autre décision se fonder sur elle sans connaître sa fraîcheur. Déclarer le délai et prévoir une source de vérification protège les parcours sensibles.

Généraliser une transaction globale

Étendre une transaction à des dépendances réseau ou à plusieurs domaines peut augmenter fortement indisponibilité et couplage. Préférer des invariants locaux, des transitions explicites et une compensation lorsque la cohérence globale immédiate n'est ni réaliste ni nécessaire.

Bonnes pratiques

Écrire les garanties temporelles dans les contrats

Pour une API, un événement ou une projection, préciser ce qui est garanti : ordre par entité ou non, doublons possibles, délai de propagation, durée d'une décision, version attendue et comportement lors d'un conflit. Les consommateurs peuvent alors concevoir une réponse sûre au lieu d'inférer des propriétés fragiles.

Tester les comportements perturbés

Ajouter des scénarios de doublon, retard, inversion, expiration et concurrence aux tests de contrat ou de composant. Ces tests n'ont pas besoin de simuler tout le réseau ; ils doivent démontrer les décisions de domaine prises lorsque les hypothèses de chemin nominal échouent.

Checklist — Le système tient-il dans le temps réel ?

  • Quel temps définit l'effet métier, le traitement et l'observation de ce changement ?
  • Quelles opérations peuvent être concurrentes et quel résultat de conflit est acceptable ?
  • Les doublons, retards et inversions sont-ils possibles à cette frontière ?
  • Quelle clé ou version distingue une répétition d'une nouvelle intention ?
  • La fraîcheur d'une projection est-elle visible avant une décision sensible ?
  • Quelle réconciliation détecte les états qui ne peuvent pas être résolus en ligne ?

À retenir

Le temps et la concurrence ne sont pas des détails d'infrastructure. Ils déterminent le sens d'une décision métier. Les rendre explicites dans les contrats, les données et les tests évite que l'ordre, la fraîcheur ou le retry deviennent des règles cachées de production.