Passer au contenu
DedicatedPHP Contact

Les tentatives ne suffisent pas : concevoir la réconciliation des tâches asynchrones en PHP

Apprenez à vérifier les résultats métier, détecter les incohérences et réparer les tâches asynchrones en PHP sans vous fier aux seules tentatives.

Diagramme de réconciliation de tâches asynchrones dans une application PHP

Les tâches asynchrones permettent de découpler les importations, les synchronisations, les notifications, la génération de documents et les intégrations. Toutefois, le fait qu’un consommateur ait traité un message ne démontre pas nécessairement que le résultat métier est correct. Un succès peut avoir été enregistré avant la confirmation d’un effet externe, une panne peut s’être produite entre deux étapes ou la même opération peut avoir été exécutée plus d’une fois.

La réconciliation des tâches asynchrones en PHP couvre cet écart : elle compare ce que le système devait obtenir avec les preuves de ce qui s’est produit, détecte les absences ou les divergences et déclenche une correction contrôlée. Elle ne remplace ni la file, ni les tentatives, ni l’idempotence ; elle les complète par une vérification indépendante.

Une exécution technique n’équivaut pas à un résultat métier

Une exécution technique n’équivaut pas à un résultat métier — guía visual de DedicatedPHP

Une tâche peut se terminer sans exception et laisser malgré tout un processus incomplet. Par exemple, une application crée une demande de synchronisation, le consommateur appelle une API externe et reçoit une réponse non concluante à la suite d’une coupure réseau. S’il réessaie sans clé idempotente, il peut créer un doublon. S’il suppose la réussite, il peut laisser l’enregistrement non synchronisé.

Il ne faut pas non plus tenir pour acquise une sémantique de livraison précise de l’infrastructure de messagerie. La possibilité de redeliveries et d’exécutions dupliquées dépend du broker, de sa configuration de persistance, des acquittements, du comportement du consommateur et des pannes qui se produisent. La conception doit vérifier ces propriétés dans la technologie choisie et, lorsque des doublons ou des réordonnancements peuvent se produire, les tolérer explicitement.

La question opérationnelle n’est pas seulement « le message a-t-il été consommé ? », mais « puis-je démontrer que l’effet attendu existe, une seule fois lorsque cela est pertinent, et avec les bonnes données ? ». Cette démonstration exige une source de preuve : une réponse interrogeable du système externe, un identifiant distant persisté, un document stocké ou un changement d’état confirmé.

Tentatives, idempotence et réconciliation : des responsabilités distinctes

Les tentatives traitent les erreurs transitoires : indisponibilité temporaire, limites d’utilisation, blocages brefs ou problèmes réseau. Il convient de définir une limite de tentatives, un délai progressif, une classification des erreurs et une destination pour les messages nécessitant une attention. Réessayer indéfiniment peut masquer une erreur de données ou aggraver un incident externe.

L’idempotence rend sûre la répétition d’une opération. Elle peut être obtenue avec un identifiant d’opération stable envoyé à un fournisseur externe, une contrainte unique en base de données ou une vérification transactionnelle avant l’effet. Cela ne signifie pas que l’effet s’est produit : cela signifie qu’une répétition ne devrait pas le multiplier.

La réconciliation recherche les opérations en attente, incomplètes ou contradictoires et décide quoi faire pour chacune d’elles. Elle est particulièrement nécessaire lorsqu’il existe des effets externes, des traitements par lots, des mises à jour de plusieurs systèmes ou des communications dont la réception ne peut pas être prouvée uniquement depuis l’application émettrice.

  • Utilisez les tentatives pour réessayer les échecs classés comme transitoires.
  • Utilisez l’idempotence pour empêcher que les tentatives ou les redeliveries dupliquent les effets.
  • Utilisez la réconciliation pour vérifier l’état final et réparer les écarts détectés.

Modéliser l’opération et conserver des preuves vérifiables

Une conception maintenable sépare trois concepts. La tâche demandée représente l’intention, par exemple, « synchroniser la commande 452 ». L’effet attendu définit le résultat observable : « le système externe contient la commande avec la version 7 ». La confirmation stocke la preuve que ce résultat existe : identifiant distant, version, horodatage, réponse validée ou résultat d’une requête ultérieure.

Avant de publier un message, créez un enregistrement d’exécution dans une base de données durable. Si l’application modifie ses propres données et publie un message, envisagez le pattern outbox : enregistrez la modification métier et l’événement en attente dans la même transaction, puis déléguez la publication à un processus ultérieur. Cela réduit le risque de confirmer la modification locale et de perdre le message, ou de publier un message pour une modification qui a été annulée.

L’enregistrement doit inclure, au minimum :

  • operation_id immuable et unique, utilisé pour corréler les messages, les logs et les appels externes.
  • Le type d’opération, l’entité affectée et la version ou l’empreinte du contenu attendu.
  • L’état actuel, le nombre de tentatives, la prochaine tentative autorisée et les horodatages.
  • La clé idempotente et, s’il existe, l’identifiant de la ressource distante.
  • Des preuves synthétisées et des références sûres aux réponses ou aux erreurs, sans enregistrer de secrets ni de données personnelles inutiles.
  • Le motif de clôture, de compensation, d’abandon ou d’escalade vers une revue humaine.

Définissez des transitions explicites, par exemple : pending, processing, awaiting_confirmation, confirmed, retry_scheduled, manual_review, compensated et not_applicable. Chaque transition doit avoir un responsable et une condition vérifiable. Une mise à jour conditionnelle, telle que le passage à processing uniquement si l’état précédent est pending, réduit les conditions de concurrence entre consommateurs.

Construire le processus de réconciliation

La réconciliation peut s’exécuter au moyen d’une commande PHP planifiée, d’un worker dédié ou d’un flux opérationnel. Elle doit travailler avec des fenêtres temporelles : n’examinez pas les opérations créées il y a quelques secondes si l’intégration externe prend normalement plusieurs minutes. Définissez la fenêtre à partir de données réelles de latence et réévaluez-la lorsque les limites ou les fournisseurs changent.

Pour chaque opération éligible, comparez des sources de vérité préalablement définies. La base locale peut faire autorité sur l’intention et la version de la donnée ; le système externe, sur le fait qu’il a reçu ou créé la ressource. Lorsqu’il n’existe pas de requête fiable vers la destination, la preuve peut être un accusé de réception signé, un identifiant de fournisseur ou une vérification différée au moyen d’un fichier de résultats.

  1. Sélectionnez les opérations non confirmées qui dépassent leur délai attendu.
  2. Vérifiez si l’effet existe à l’aide de operation_id, de la clé idempotente ou d’une clé métier non équivoque.
  3. Comparez les champs pertinents et les versions, et non uniquement l’existence de la ressource.
  4. Classez le cas comme absent, correct, divergent, ambigu ou non applicable.
  5. Exécutez l’action autorisée et enregistrez la décision avec ses preuves.

Un résultat ambigu ne doit pas automatiquement devenir une remise en file. Si un appel a pu créer une ressource mais qu’il n’existe aucun moyen de l’interroger de manière fiable, réessayer pourrait dupliquer un paiement, une notification ou un document. Dans ces cas, bloquez l’action automatique et envoyez le cas vers un tableau des exceptions avec un contexte suffisant pour décider.

Corriger sans introduire de nouveaux dommages

L’action dépend de l’écart et du coût d’une erreur. Remettre en file convient lorsque l’effet est absent et que l’opération est idempotente. Compenser peut annuler un effet incorrect au moyen d’une opération métier explicite, et non par une suppression technique indiscriminée. Marquer pour revue est préférable en cas d’ambiguïté, de conflit de versions ou de conséquences financières. Clôturer comme non applicable convient lorsque l’entité a été annulée ou remplacée conformément à des règles documentées.

Les réparations manuelles doivent également laisser une trace : qui a pris la décision, quelles preuves ont été consultées, quelle action a été appliquée et quel en a été le résultat. Limitez les autorisations et évitez les boutons qui exécutent une opération sans afficher l’entité, la version, la destination et le risque de duplication.

Observabilité et tests qui valident la conception

Les logs corrélés par operation_id facilitent le suivi d’une opération entre le web, les workers et les services externes. Les métriques utiles ne se limitent pas aux exceptions : mesurez l’ancienneté des opérations en attente, le nombre d’opérations en revue manuelle, le taux de divergences, les tentatives par cause et le délai jusqu’à confirmation. Les alertes doivent se déclencher en cas d’accumulation, d’ancienneté ou de non-respect du délai, et non pour chaque erreur isolée.

Testez des pannes représentatives : panne après l’effet externe et avant la persistance de la confirmation ; exécution dupliquée ; message reçu dans le désordre ; redémarrage du worker ; timeout avec résultat distant incertain ; indisponibilité prolongée ; et changements de version alors qu’une opération reste en attente. Le test doit vérifier à la fois l’état final, l’absence de doublons et la qualité des preuves stockées.

Exemple : synchroniser un enregistrement avec un système externe

Supposez qu’une application PHP synchronise un enregistrement client. Lors de sa modification, elle crée l’opération sync_customer avec un identifiant stable et la version locale attendue. Le worker envoie ces valeurs à la destination comme clé idempotente. S’il reçoit une confirmation valide, il persiste l’identifiant distant et passe l’état à confirmed.

Si le timeout survient après l’envoi de la requête, le worker laisse l’opération dans l’état awaiting_confirmation. Le réconciliateur interroge la destination à l’aide de la clé idempotente. S’il trouve la même version, il confirme. S’il ne la trouve pas, il planifie un nouvel envoi. S’il trouve une version différente, il marque le cas pour revue au lieu d’écraser des données qui pourraient avoir été légitimement modifiées dans l’autre système.

Checklist pour intégrer la réconciliation sans réécrire le processus

Checklist pour intégrer la réconciliation sans réécrire le processus — guía visual de DedicatedPHP
  • Inventoriez les tâches existantes et donnez la priorité à celles qui produisent des effets externes, concernent de l’argent, des données réglementaires ou des processus difficiles à répéter.
  • Pour chaque type, documentez l’effet attendu, la source de vérité et les preuves qui permettront de le confirmer.
  • Vérifiez dans le broker et les consommateurs concernés ce qui se produit lors de pannes, d’acquittements tardifs, de persistance, de redelivery et d’ordre des messages.
  • Ajoutez un operation_id stable et propagez-le dans le message, les logs, les appels externes et les enregistrements d’état.
  • Introduisez une table d’opérations avec des états, des tentatives, des délais, une clé idempotente et des preuves ; commencez en mode observation si nécessaire.
  • Définissez des transitions conditionnelles et une politique écrite pour réessayer, confirmer, compenser, escalader ou clôturer comme non applicable.
  • Implémentez un réconciliateur limité à une fenêtre temporelle et à un type d’opération pilote.
  • Validez avec des cas de doublon, de timeout ambigu, de panne entre étapes, de réordonnancement et de redémarrage avant d’automatiser les corrections.
  • Créez un tableau ou une requête d’exceptions avec l’ancienneté, l’entité, les preuves et l’action recommandée.
  • Examinez régulièrement les métriques, les opérations bloquées et les décisions manuelles afin d’ajuster les délais, les règles et les contrôles.

L’adoption progressive permet d’améliorer la fiabilité sans remplacer toute l’architecture : rendez d’abord visibles les opérations incertaines, confirmez ensuite les résultats et, enfin, automatisez uniquement les corrections dont vous pouvez démontrer la sûreté.

Vous souhaitez appliquer ces idées à votre projet ?Parlons de votre plateforme PHP.
Afficher les services associés