Dans cet article, nous allons apprendre à utiliser superviseur pour gérer l'exécution d'une commande symfony. En gros, superviseur va nous permettre de :
Parfois, nous avons recours à la crontab Unix pour automatiser l'exécution des processus. Cela peut fonctionner la plupart du temps, mais il peut y avoir des situations où cela peut causer des problèmes.
Imaginons que nous ayons une table de base de données qui enregistre les notifications des utilisateurs. Le tableau stocke les informations suivantes :
D'autre part, nous avons codé une commande dont l'exécution suit les étapes suivantes :
Nous avons défini cette commande dans la crontab Linux pour qu'elle s'exécute de temps en temps (1 minute, 2 minutes, etc.). Jusqu’ici tout va bien.
Imaginons maintenant que le processus actuel ait interrogé 500 notifications et qu'après en avoir envoyé 400, un nouveau processus démarre. Cela signifie que le nouveau processus interrogera les 100 notifications qui n'ont pas encore été mises à jour par le dernier processus ainsi que les nouvelles :
Cela peut entraîner l'envoi de ces 100 notifications deux fois puisque les deux processus les ont interrogées.
Comme solution, nous pouvons recourir à l'utilisation d'un superviseur. Il maintiendra notre processus en cours et le redémarrera si nécessaire. De cette façon, nous ne conservons qu’un seul processus et évitons les chevauchements. Analysons à quoi devrait ressembler la commande :
#[AsCommand( name: 'app:notification' )] class NotificationCommand extends Command { private bool $forceFinish = false; protected function configure(): void { $this ->addOption('time-limit', null, InputOption::VALUE_OPTIONAL, 'Max time alive in seconds') ->addOption('time-between-calls', null, InputOption::VALUE_OPTIONAL, 'Time between every loop call') ; } protected function execute(InputInterface $input, OutputInterface $output): int { $this->forceFinish = false; pcntl_signal(SIGTERM, [$this, 'signalHandler']); pcntl_signal(SIGINT, [$this, 'signalHandler']); $timeLimit = $input->getOption('time-limit'); $timeBetweenCalls = $input->getOption('time-between-calls'); $dtMax = (new \DateTimeImmutable())->add(\DateInterval::createFromDateString("+ {$timeLimit} seconds")); do{ // Here we should execute a service to query and send notifications // ...... sleep($timeBetweenCalls); $dtCurrent = new \DateTimeImmutable(); }while($dtCurrent < $dtMax && !$this->forceFinish); return Command::SUCCESS; } public function signalHandler(int $signalNumber): void { echo 'Signal catch: ' . $signalNumber . PHP_EOL; match ($signalNumber) { SIGTERM, SIGINT => $this->forceFinish = true, default => null }; } }
Expliquons la commande étape par étape :
La méthode configure déclare aux options de saisie :
La méthode execute se comporte comme suit :
La fonction signalHandler capte les signaux SIGTERM et SIGINT Unix. SIGINT est le signal envoyé lorsque nous appuyons sur Ctrl+C et SIGTERM est le signal par défaut lorsque nous utilisons la commande kill. Lorsque la fonction signalHandler les détecte, elle définit la variable forceFinish sur true afin que, lorsque la boucle en cours se termine, la commande se termine puisque la variable forceFinish est n'est plus faux. Cela permet aux utilisateurs de terminer le processus sans avoir à attendre que la date maximale soit terminée.
Jusqu'à présent, nous avons créé la commande. Il est maintenant temps de configurer le superviseur pour qu'il puisse le gérer. Avant de commencer la configuration, nous devons installer le superviseur. Vous pouvez le faire en exécutant la commande suivante :
sudo apt update && sudo apt install supervisor
Après l'installation, vous pouvez vous assurer que le superviseur est en cours d'exécution en exécutant la commande suivante :
sudo systemctl status supervisor
Les fichiers de configuration du superviseur sont placés dans le dossier suivant : /etc/supervisor/conf.d. Créons un fichier nommé notif.conf et collons le contenu suivant :
command=php <your_project_folder>/bin/console app:notifications --time-limit=120 --time-between-calls=10 user=<your_user> numprocs=1 autostart=true autorestart=true process_name=%(program_name)s_%(process_num)02d
Expliquons chaque clé :
Avec cette configuration, la commande app:notifications s'exécutera pendant un maximum de 120 secondes et elle dormira pendant 10 secondes après chaque boucle. Après avoir passé 120 secondes ou mis en cache un signal Unix, la commande quittera la boucle et se terminera. Ensuite, le superviseur le redémarrera.
Nous avons appris à utiliser le superviseur pour maintenir une commande en cours d'exécution sans avoir à utiliser la crontab. Cela peut être utile lorsque les processus lancés par la crontab peuvent se chevaucher, provoquant une corruption des données.
Dans le dernier livre que j'ai écrit, je montre comment utiliser le superviseur pour que les travailleurs de messagerie Symfony continuent de fonctionner. Si vous souhaitez en savoir plus, vous pouvez trouver le livre ici : Construire une API orientée opérations à l'aide de PHP et du framework Symfony : un guide étape par étape
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!