par , 22/04/2023 à 11h18 (1313 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 :
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 :
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.