Éviter la double éxécution d'une commande Symfony sur Linux

Retour aux articles Dans #php le 03/10/2016 par Emmanuel BALLERY

Éviter la double éxécution d'une commande Symfony sur Linux

Certaines commandes PHP nécessitent parfois de ne pas être éxécutées deux fois en même temps (posséder deux instances). Prenons par exemple une commande qui dépile des emails pour les importer dans un système, que nous éxécutons à interval régulier. Nous ne gérons pas le temps que va prendre cette tâche. Dans certains cas, il n'y aura pas ou peu de mail, la réalisation sera quasi-instantannée. Dans d'autres cas, il y aura des centaines de mails, et la durée d'éxécution va flamber. Cependant, pendant que cette commande s'éxécute, nous ne voulons pas qu'une autre instance tourne. Elle pourrait analyser et importer les mêmes emails plusieurs fois dans le système et créer des doublons.

La solution repose sur la création d'un fichier de lock (lock file) sur le disque lorsque la commande s'éxécute. Lorsqu'une autre instance de cette commande sera créée, elle détectera ce fichier de lock, indiquant que ce travail est déjà en cours, et s'arretera.

Les cas d'erreur seront gérés en stockant dans ce fichier le PID de la commande en cours (voir https://fr.wikipedia.org/wiki/PID). En effet, si une erreur se produit, ou que la commande est interrompue, le fichier de lock ne sera pas supprimé. Il faut donc pouvoir tester si la commande initiale est encore en cours d'éxécution grâce à son PID.

Workflow

La commande est éxécutée, elle cherche un fichier de lock sur le disque :

  1. Il n'y a pas de fichier de lock :
    1. Elle crée un fichier de lock et y inscrit son PID ;
    2. Elle réalise son action puis s'arrête (sans même avoir besoin de supprimer le fichier de lock) ;
  2. Un fichier de lock est présent, elle récupère le PID stocké dans ce fichier et demande au système si ce processus est encore actif :
    1. Le processus est encore actif, la commande s'arrête pour éviter le doublon ;
    2. Le processus n'est plus actif, la commande s'éxécute comme s'il n'y avait pas de fichier de lock ;

Implémentation

En Symfony, on peut créer une classe abstraite, dont héritera notre commande. Cette classe conditionnera l'éxécution de notre logique à la série de vérifications que nous avons listé ci-dessus;

Utilisation

Pas de magie, il suffit d'hériter de cette classe abstraite.

Retour aux articles