IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Séb.

PHP CLI et gestion du signal d'interruption

Noter ce billet
par , 22/04/2023 à 10h18 (1178 Affichages)
J'intègre et traite de la data toute la journée. Pour cela un script PHP CLI tourne en permanence, et dès que du nouveau arrive, c'est inséré en base de données, transmis par e-mail, déposé sur un WebDAV ou un SFTP, historisé, archivé, etc.

Une belle mécanique, mais soudainement bien fragile dès qu'une maintenance est nécessaire. Que se passe-t-il si le script est interrompu en pleine écriture d'un fichier ? Les fichiers risquent d'être corrompus, des transactions SQL sont à annuler, des joyeusetés que l'on préfère éviter.

La solution : détecter le signal d'interruption et stopper le script un instant plus tard, dans un état stable, après la réalisation de la tâche.

PHP permet cela grâce aux fonctions PCNTL.

Squelette :

Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
while (true) {
    $task = task_accept(); // Non bloquant, tente de récupérer une nouvelle tâche
    if ($task !== null) {
        echo "Débute {$task->name}\r\n";
        task_run($task); // Peut s'exécuter pendant plusieurs minutes
        echo "Termine {$task->name}\r\n";
    }
}

Implémentation de la gestion du signal d'interruption SIGINT émis par CTRL+C, kill -SIGINT ou kill -2 :

Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Enregistrement du gestionnaire de signal SIGINT
// Réagit à CTRL+C ou kill -2
pcntl_signal(SIGINT, function (int $signo, mixed $siginfo) use (&$interrupt_received) {
    echo "Demande d'interruption bien reçue et honorée dès que possible\r\n";
    $interrupt_received = true;
});
 
// Drapeau indiquant si une demande d'interruption a été reçue
// Modifié par le gestionnaire SIGINT déclaré précédemment
$interrupt_received = false;
 
while (true) {
    if ($interrupt_received) {
        exit(0);
    }
    $task = task_accept(); // Non bloquant, tente de récupérer une nouvelle tâche
    if ($task !== null) {
        echo "Débute {$task->name}\r\n";
        task_run($task); // Peut s'exécuter pendant plusieurs minutes
        echo "Termine {$task->name}\r\n";
    }
}

Grâce à ces quelques lignes, toute interruption du script est interceptée et honorée uniquement en début de boucle, hors exécution d'une tâche.

Le même principe peut être appliqué pour d'autres signaux, comme SIGTERM.

SIGKILL (kill -9), quant à lui, n'est pas interceptable.

Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Viadeo Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Twitter Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Google Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Facebook Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Digg Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Delicious Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog MySpace Envoyer le billet « PHP CLI et gestion du signal d'interruption » dans le blog Yahoo

Mis à jour 22/04/2023 à 13h30 par Séb.

Tags: cli, php, signal
Catégories
Programmation

Commentaires