Les signaux POSIX et PHP
Après la conférence d’Alexandre Balmes sur les signaux, les PID et leur gestion en PHP au ForumPHP 2017, nous avons souhaité écrire un article récapitulatif de ce que sont les signaux, comment ils fonctionnent au niveau système, et comment les utiliser en PHP.
Les signaux et process identifier (PID) sont souvent méconnus des développeurs PHP. Pourtant, ils sont très utiles et même indispensables lorsque nous devons travailler avec des tâches qui vont s’exécuter via la ligne de commande : un script d’import de données, un cron ou un worker RabbitMQ.
Section intitulée pidPID
Mais qu’est-ce qu’un PID ? Ce n’est rien de plus qu’un identifiant. Chaque processus en possède un. Ils commencent à 1 et vont en s’incrémentant. Le processus ayant pour PID 1 est donc le premier processus à s’être lancé sur le système. Sur une majorité de distributions Linux, ce processus sera systemd. Pour rappel, systemd est désormais le gestionnaire d’initialisation des processus sous Debian depuis sa version 8 et sur Red Hat depuis sa version 7. La commande ps -q 1
permet de vérifier quel est le gestionnaire de processus.
Vous vous êtes peut-être demandé à quoi correspondent les dossiers dans le dossier /proc
de votre système ? À chaque dossier correspond un processus. Chaque dossier a pour nom le PID du processus. Dans ce dossier, nous pouvons retrouver entre autres, les variables d’environnement qui ont été passées au processus.
Certaines tâches ne doivent pas pouvoir s’exécuter en parallèle. Nous pourrions utiliser le PID pour bloquer une deuxième commande qui voudrait se lancer. Cela dit, la meilleure solution est d’utiliser flock
s’il n’y a qu’un seul serveur qui exécute le code. Symfony a une implémentation de la version 2.6 à 3.4. Celle-ci a été dépréciée et remplacée par le composant Lock à partir de la version 3.4. Ce composant permet entre autres d’avoir des locks distribués. C’est notamment utile quand le code peut s’exécuter sur plusieurs serveurs.
Section intitulée signauxSignaux
Pour commencer, il faut savoir que les signaux ne sont pas vraiment supportés par Windows. En effet, Windows n’utilise pas la norme POSIX.
Qu’est-ce qu’un signal ? Pour faire simple, c’est une notification envoyée par le système d’exploitation, un utilisateur du système, ou un autre programme à un processus de manière asynchrone. Par exemple, c’est utilisé pour dire à un processus qu’il doit s’arrêter proprement. Il existe 31 signaux différents et à chaque signal, son utilité.
Pour arrêter proprement un processus, il faut envoyer un SIGINT
via la commande kill -2 PID
ou via CTRL+C
pour annoncer au processus qu’il doit s’arrêter. Pour rappel, CTRL+C
est un raccourci clavier qui va envoyer un SIGINT
(2) au processus qui est en train de tourner. Le processus va alors recevoir ce signal et pourra alors décider du meilleur moment pour s’arrêter. Tout ceci afin qu’il ne coupe pas en plein milieu d’une transaction par exemple.
Section intitulée quand-les-utiliserQuand les utiliser ?
L’utilisation des signaux est très utile pour garantir l’intégrité des donnés manipulées par un programme. Ils permettent d’éviter qu’un autre processus ou qu’un humain arrête le processus en plein milieu d’un traitement. Imaginons qu’un programme doive s’occuper de la facturation périodique d’un site. Ce programme a pour but de sélectionner dans la BDD les abonnements qui doivent être renouvelés, appeler une API de paiement pour procéder à la transaction, envoyer un email à l’utilisateur puis enfin mettre à jour la BDD. Il est évident qu’il ne faut pas que le programme puisse s’arrêter en plein milieu du traitement.
Section intitulée comment-les-utiliser-en-phpComment les utiliser en PHP ?
Pour pouvoir utiliser les signaux en PHP, l’extension pecl pcntl est nécessaire.
L’utilisation est très simple. Il faut d’abord installer un gestionnaire de signaux grâce à la fonction pcntl_signal
. Ce n’est rien de plus qu’une fonction qui sera appelée quand PHP annoncera qu’un signal est arrivé. En effet, PHP va bufferiser les signaux qu’il reçoit. C’est seulement lors de l’appel à la fonction pcntl_signal_dispatch
que le gestionnaire de signaux sera exécuté.
Voici un exemple de code qui tire parti de ces deux fonctions. Si vous essayez de l’exécuter, vous noterez qu’il y a toujours un ABC
qui s’affiche quel que soit le moment ou vous utilisez CTRL+C
.
class Daemon
{
// Par défaut, nous n'arrêtons pas le processus.
private $shouldStop = false;
public function __construct()
{
// Nous installons un gestionnaire de signaux qui va capturer les signaux SIGINT (CTRL+C)
pcntl_signal(SIGINT, function () {
// Au moment où PHP va dispatcher le signal, nous allons stocker le fait
// qu'il faut s'arrêter.
$this->shouldStop = true;
});
}
public function run()
{
while (true) {
// Boucle de traitement
echo "A";
sleep(1);
echo "B";
// Dispatch des signaux qui ont été buffurisés par PHP
pcntl_signal_dispatch();
sleep(1);
echo "C\n";
// Si un signal a été dispatché, alors nous pouvons arrêter proprement le script
// car celui-ci a réellement fini de travailler.
if ($this->shouldStop) {
echo "\nThe program is going to quit.\n";
break;
}
}
}
}
$daemon = new Daemon();
$daemon->run();
Section intitulée remarquesRemarques
Vous verrez peut-être dans certains scripts PHP l’utilisation des ticks pour contrôler le buffering des signaux, il ne faut surtout pas utiliser ce mécanisme car vous n’aurez aucun contrôle sur ce dispatch. Tout l’intérêt des signaux est justement de contrôler quand ce dispatch a lieu.
Depuis PHP 7.1, il est possible de se passer de la fonction pcntl_signal_dispatch
. Il suffit d’appeler tout au début du script pcntl_async_signals(true)
. Mais ce système a le même inconvénient que l’usage des ticks. Néanmoins, grâce à une variable shouldStop
comme dans l’exemple précédent, nous contrôlons le moment où le code peut s’arrêter. L’usage de pcntl_async_signals(true)
n’est donc pas vraiment un problème. Mais le code peut ne pas être toujours aussi simple.
Section intitulée conclusionConclusion
Au même titre que les codes de retour, les signaux et les PID sont les deux pierres angulaire de la gestion de processus sous Unix. Et vos tâches PHP doivent les exploiter pour gagner en robustesse !
Symfony 4.1 proposera sûrement un nouveau composant dédié pour gérer les workers en PHP et il utilisera évidemment les signaux.
Commentaires et discussions
Ces clients ont profité de notre expertise
Nous avons entrepris une refonte totale du site, initialement développé sur Drupal, afin de le rendre plus solide et de construire l’avenir sur des bases solides en utilisant Symfony. La plateforme est complexe et propose de nombreuses fonctionnalités telles que la gestion d’abonnements avec Stripe et Paypal, une API pour l’application mobile, le transcoding…
À l’occasion de la 12e édition du concours Europan Europe, JoliCode a conçu la plateforme technique du concours. Ce site permet la présentation des différents sites pour lesquels il y a un appel à projets, et encadre le processus de recueil des projets soumis par des milliers d’architectes candidats. L’application gère également toute la partie post-concours…
Armadillo édite un moteur de base de données spécialisé dans la gestion de données multimédias et des métadonnées associées. Depuis de nombreuses années, cette plateforme est accessible par le biais d’un connecteur PDO pour PHP, dont nous avons facilité l’intégration en développant une librairie PSR-0 ainsi qu’un bundle Symfony. Notre mission a principalement…