Ответ 1
PHP Script также может перезапустить себя с помощью PCNTL.
Отказ от ответственности: точка этого упражнения заключается только в том, чтобы доказать, что PHP вполне способен перезапустить себя и ответить на вопрос:
Есть ли способ автоматически перезапустить PHP Script всякий раз, когда он выходит, независимо от того, был ли он завершен должным образом или завершился из-за ошибки?
Именно поэтому мы можем подробно рассказать о процессах unix, поэтому я предлагаю вам начать с PCNTL book или обратиться к php-pcntl для получения более подробной информации.
В примерах мы предположим, что это CLI-интерфейс CLI Script, запущенный в среде * nix из терминала с полупристойной оболочкой с помощью команды:
$ php i-can-restart-myself.php 0
Мы передаем атрибут подсчета перезапуска в качестве индикатора, что процесс был перезапущен.
Можно ли автоматически перезапустить PHP Script?
Да, я могу!
<?php
echo ++$argv[1]; // count every restart
$_ = $_SERVER['_']; // or full path to php binary
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n========== end =========\n";
// restart myself
pcntl_exec($_, $argv);
Независимо от того, было ли оно правильно завершено?
Да, я могу перезапустить, если он завершен!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
register_shutdown_function(function () {
global $_, $argv; // note we need to reference globals inside a function
// restart myself
pcntl_exec($_, $argv);
});
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
Или завершено из-за ошибки?
То же самое!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
register_shutdown_function(function () {
global $_, $argv;
// restart myself
pcntl_exec($_, $argv);
});
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
Но вы знаете, что я хочу больше, чем это правильно?
Конечно! Я могу перезапустить на kill, hub даже Ctrl-C!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
$restartMyself = function () {
global $_, $argv;
pcntl_exec($_, $argv);
};
register_shutdown_function($restartMyself);
pcntl_signal(SIGTERM, $restartMyself); // kill
pcntl_signal(SIGHUP, $restartMyself); // kill -s HUP or kill -1
pcntl_signal(SIGINT, $restartMyself); // Ctrl-C
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
Как мне его закончить?
Если вы наполнили процесс, удерживая Ctrl-C, вы можете просто поймать его где-нибудь в выключении.
Я не хочу, чтобы все эти ошибки можно было перезапустить тоже?
Нет проблем, я тоже могу обрабатывать ошибки!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
$restartMyself = function () {
global $_, $argv;
pcntl_exec($_, $argv);
};
register_shutdown_function($restartMyself);
pcntl_signal(SIGTERM, $restartMyself);
pcntl_signal(SIGHUP, $restartMyself);
pcntl_signal(SIGINT, $restartMyself);
set_error_handler($restartMyself , E_ALL); // Catch all errors
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo $CAREFUL_NOW; // NOTICE: will also be caught
// we would normally still go here
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
Хотя на первый взгляд это работает нормально, потому что pcntl_exec работает в том же процессе, мы не замечаем, что вещи ужасно ошибочны. Если вы хотите создать новый процесс и позволить старому умереть вместо этого, что является вполне жизнеспособной альтернативой, см. Следующий пост, вы заметите, что на каждой итерации запускается 2 процесса, потому что мы запускаем PHP NOTICE и ERROR из-за общего контроля, Который, конечно, может быть легко исправлен, гарантируя, что мы умрем() или exit() после вызова pcntl_exec в обработчике ошибок, иначе PHP предполагает, что допуски были приняты и продолжаются.
То, что я пытаюсь сделать, состоит в том, что даже если вы можете перезапустить Script, что не удалось, это не повод для отказа от кода. Хотя для этой практики могут существовать жизнеспособные варианты использования, Я категорически не согласен с тем, что перезапуск при сбое должен использоваться как решение для сбоев сценариев из-за ошибок! Как мы можем видеть из этих примеров, нет способа зная точно, где он потерпел неудачу, поэтому мы не можем быть уверены, где он начнется снова. Переход на решение "быстрого исправления", которое может показаться работоспособным, может иметь больше проблем, чем раньше.
Вместо этого я предпочел бы увидеть дефект, адресованный некоторыми надлежащими модульными тестами, которые помогут вымыть преступника, чтобы мы могли исправить проблему. Если у PHP заканчивается память, его можно избежать за счет консервативного использования ресурсов, отключив переменные после использования. (Кстати, вы найдете назначение нулевого значения намного быстрее, чем использование unset для одного и того же результата). Я боюсь, хотя, если вы останетесь не решенным, перезапуск будет определенно служить подходящим открывателем для банки червей, которые у вас уже есть.