Passer au contenu
DedicatedPHP Contact

Comment concevoir des transactions par lots pour les imports PHP

Découvrez comment choisir les limites transactionnelles, enregistrer des points de contrôle et reprendre des imports PHP sans dupliquer les modifications ni masquer les erreurs partielles.

Schéma éditorial d’un import PHP réparti en lots avec transactions, points de contrôle et reprise après erreur

Un import volumineux peut échouer à cause d’une connexion interrompue, d’une donnée invalide ou d’une limite de temps du processus. Si toutes les modifications dépendent d’une seule transaction, le système peut conserver des verrous trop longtemps et perdre tout le travail qui n’a été validé qu’à la fin. À l’inverse, si chaque ligne est enregistrée indépendamment sans stratégie de reprise, une interruption peut laisser des données incohérentes.

Concevoir des transactions par lots pour les imports PHP consiste à choisir des unités de travail pouvant être validées, suivies et rejouées en toute sécurité. Cela ne revient pas à rendre l’import entier atomique : en général, chaque lot est atomique individuellement et le processus complet peut être partiellement appliqué. Cette distinction doit se refléter à la fois dans l’implémentation et dans l’expérience opérationnelle.

Pourquoi une transaction unique peut être inadaptée

Pourquoi une transaction unique peut être inadaptée — guía visual de DedicatedPHP

Une transaction longue peut retenir des verrous, accroître la pression sur le journal des transactions et entrer en concurrence avec les requêtes de l’application. Si l’import traite des millions de lignes, il est également difficile de savoir ce qu’il reste à faire et comment réagir après un échec. Le comportement exact dépend du moteur de base de données, du niveau d’isolation et du volume d’écritures ; il est donc préférable de le mesurer dans l’environnement réel.

Valider chaque ligne réduit la durée de chaque transaction, mais peut multiplier le coût des validations et laisser des dépendances entre lignes partiellement appliquées. Le lot constitue un compromis : si une opération du groupe échoue et que l’exception se propage, ce groupe est annulé ; les lots déjà validés sont conservés. L’application doit présenter cette situation comme une progression partielle, et non comme une réussite globale ou un rollback complet.

Choisir la limite transactionnelle appropriée

L’unité ne doit pas nécessairement correspondre à un nombre fixe de lignes. Elle doit représenter des modifications pouvant être validées et persistées de manière cohérente. Si chaque enregistrement est indépendant, un lot de lignes peut suffire. Si plusieurs enregistrements constituent une entité métier — par exemple, un en-tête et ses lignes —, les conserver dans la même transaction évite d’enregistrer une entité incomplète.

Pour choisir la taille, évaluez la durée de chaque lot, le volume de mémoire, la contention sur les tables partagées, la fréquence des erreurs et le coût de la reprise du travail. Un lot important réduit le nombre de validations, mais prend plus de temps à traiter et augmente le volume de travail à refaire en cas d’échec. Un lot plus petit limite ce coût, mais accroît la surcharge et peut nuire aux performances. Il n’existe pas de taille universelle : commencez par une valeur configurable et ajustez-la au moyen de tests de charge représentatifs.

En PHP, évitez de charger le fichier entier en mémoire s’il peut être parcouru progressivement. Lisez un nombre limité de lignes, validez leurs champs, démarrez la transaction, effectuez les écritures et validez. En cas d’erreur, annulez la transaction du lot et classez l’échec. Avec PDO, par exemple, le contrôle peut s’exprimer à l’aide de beginTransaction(), commit() et rollBack() ; la gestion des exceptions doit garantir qu’une transaction en échec ne soit pas validée.

Enregistrer la progression pour reprendre de manière fiable

Un point de contrôle indique quelle partie de la source a été traitée et validée. Il peut s’agir d’un identifiant stable, d’une position dans un fichier ou d’une clé composée, à condition de permettre la reprise sans dépendre d’un ordre susceptible de changer. Pour une requête paginée, il est généralement plus sûr d’avancer à partir d’une clé stable que d’utiliser un décalage qui peut changer si des enregistrements sont insérés ou supprimés pendant le traitement.

La progression et les modifications du lot doivent être coordonnées. Lorsque c’est possible, enregistrez les écritures métier et le nouveau point de contrôle dans la même transaction. Ainsi, si le processus s’interrompt avant la validation, une progression que la base de données n’a pas appliquée n’est pas enregistrée ; s’il valide, le curseur avance lui aussi. Si l’état d’exécution se trouve dans un autre système, cette atomicité n’est pas automatique : il faut concevoir un mécanisme de réconciliation ou accepter que des lots soient rejoués et les rendre idempotents.

Enregistrez également l’identifiant de l’import, son état, le point de contrôle, les compteurs et, le cas échéant, une référence à la version ou à l’empreinte du fichier. Lors de la reprise, vérifiez qu’il s’agit de la même entrée et d’une exécution récupérable. Définissez des états explicites, tels que en attente, en cours, terminé et en échec, ainsi qu’une politique de détection des exécutions abandonnées. Ne marquez pas un import comme terminé au seul motif que le processus s’est achevé sans lever d’exception : vérifiez qu’il a atteint la fin attendue.

Isoler les erreurs et gérer les nouvelles tentatives

Décidez à l’avance si un enregistrement invalide doit interrompre l’ensemble du traitement, être exclu ou être marqué pour examen. Pour les erreurs de format prévisibles, il peut être utile de valider les données avant d’ouvrir la transaction et d’enregistrer le motif avec un identifiant de ligne. En cas d’erreur de persistance, annulez le lot concerné. Continuer avec les lots suivants n’est raisonnable que si leurs données sont indépendantes et si l’import peut être clairement déclaré partiel.

Distinguez les erreurs permanentes — comme l’absence d’une valeur obligatoire — des défaillances transitoires — comme une interruption de connexion récupérable. Réessayer après une erreur permanente gaspille des ressources et complique le diagnostic. En revanche, une nouvelle tentative après une défaillance transitoire peut s’appuyer sur un nombre limité d’essais et un délai d’attente croissant. Si les tentatives sont épuisées, conservez suffisamment d’état et de contexte pour examiner le problème et reprendre le traitement sans masquer sa cause initiale.

Les nouvelles tentatives peuvent répéter des écritures si elles ne sont pas conçues avec soin. Utilisez des clés métier ou des identifiants source pour reconnaître les enregistrements déjà importés, et décidez si une répétition doit insérer, mettre à jour, ignorer ou signaler un conflit. Les contraintes d’unicité de la base de données peuvent renforcer cette décision, mais ne remplacent pas la logique métier. Ne faites pas du point de contrôle le seul mécanisme de prévention des doublons : il peut être désynchronisé ou ne pas couvrir les modifications effectuées par une autre voie.

Si un lot envoie également des e-mails, publie des messages ou appelle une API, la transaction de la base de données ne peut pas annuler ces effets externes. Ne les exécutez pas comme s’ils faisaient partie d’une transaction distribuée inexistante. Une solution consiste à enregistrer l’événement en attente dans une table d’outbox transactionnelle, puis à le traiter avec des nouvelles tentatives et des identifiants idempotents. Si l’effet externe échoue, l’état doit permettre de le récupérer sans dupliquer l’opération ni prétendre que le lot est entièrement terminé.

Tester la cohérence, la progression et la reprise

Les tests doivent couvrir davantage que le parcours nominal. Injectez des défaillances avant le démarrage d’une transaction, pendant les écritures, juste avant la validation et après la validation, mais avant la mise à jour d’un état externe. Vérifiez quelles données sont conservées, quel point de contrôle est maintenu et si une reprise produit le résultat attendu. Incluez des enregistrements en double, des lignes invalides, des lots vides et des erreurs de persistance.

Dans un test représentatif, mesurez la durée par lot, la mémoire, le taux d’erreur, le temps de verrouillage et la progression. Vérifiez également que les compteurs distinguent les lignes lues, acceptées, rejetées et validées ; le terme « traitées » peut être ambigu s’il inclut des modifications annulées. Les métriques et les journaux doivent identifier l’import et le lot, sans exposer de données sensibles inutiles au diagnostic.

Liste de contrôle avant la mise en production

Liste de contrôle avant la mise en production — guía visual de DedicatedPHP
  • L’unité transactionnelle correspond à une unité métier cohérente.
  • La taille du lot est configurable et a été évaluée avec des données et une charge représentatives.
  • Le point de contrôle n’avance que lorsque le lot correspondant est validé.
  • La stratégie de reprise utilise une clé stable et identifie l’entrée source.
  • Les erreurs permanentes et transitoires font l’objet de traitements distincts et observables.
  • Les opérations répétées sont idempotentes ou détectent explicitement les conflits.
  • Les effets externes sont traités selon une stratégie indépendante et récupérable.
  • Les tests vérifient des défaillances à différentes étapes, et pas seulement l’exécution complète.

L’objectif n’est pas d’empêcher toute défaillance, mais d’en limiter les conséquences et de rendre explicite l’état obtenu. Avec des limites transactionnelles réfléchies, des points de contrôle cohérents et des nouvelles tentatives sûres, un import PHP peut être repris sans confondre progression partielle et achèvement, ni appliquer à nouveau des modifications déjà validées.

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