Есть ли способ автоматически перезапустить PHP script всякий раз, когда он выходит, независимо от того, был ли он выполнен правильно или завершен из-за ошибки или максимального использования памяти и т.д.?
Автоматически перезагружать PHP скрипт на выходе
Ответ 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 для одного и того же результата). Я боюсь, хотя, если вы останетесь не решенным, перезапуск будет определенно служить подходящим открывателем для банки червей, которые у вас уже есть.
Ответ 2
Здесь будут драконы.
Расширенное использование, а не слабое сердце.
Чтобы запустить отдельный процесс, измените функцию restartMyself на:
<?php
$restartMyself = function () {
global $_, $argv;
if(!pcntl_fork()) // We only care about the child fork
pcntl_exec($_, $argv);
die; // insist that we don't tolerate errors
}
Это, безусловно, может быть приключением, преследующим процессы, которые перезапускают защиту от вашего убийства, если вам удастся поймать их в процессе. =)
Убедитесь, что у script достаточно, чтобы у вас было достаточно времени, чтобы убить его.
Try:
$ kill -9
или
$ kill -s KILL
настаивать на том, чтобы нежить оставалась мертвой. Это не простаивающая ссылка, так как вам было бы разумно рассмотреть зомби и сирот, но в конечном итоге даже самым жестким процессам, как правило, по-прежнему нужен родитель, поэтому убийство сеанса оболочки должно заставить их отдохнуть.
Все стандартные отказы распространяются, удачи! =)
Ответ 3
Предполагая, что:
- Вызовите один и тот же файл script x количество раз
- Повторный вызов, если он прерывается/завершается/останавливается
- Автоматизированный процесс для бесконечного цикла
Некоторые варианты приходят на ум для достижения вашей цели [решения на основе Unix/Linux]:
-
Используйте BASH script, так что PHP script после остановки/окончания/прерывания может быть возобновлен:
#!/bin/bash clear date php -f my_php_file.php sleep 100 # rerun myself exec $0
-
Обработчик выполнения Fat Controller - вот основные функции, которые вы ищете:
- Используется для многократного запуска других программ.
- Можно запустить несколько экземпляров любой script/программы параллельно
- любой script может быть повторно запущен, как только он завершит выполнение
очень похож на CRON, но эти ключевые функции - это именно то, что вам нужно
-
Используя CRON, вы можете позвонить ему через PHP скрипт с интервалом, например, одной минуты, затем с помощью этого кода на очень вы начнете с PHP скрипт, вы сможете контролировать количество запущенных потоков, выходящих, если 8 уже запущены:
exec('ps -A | grep ' . escapeshellarg(basename(__FILE__)) , $results); if (count($results) > 7) { echo "8 Already Running\n" die(0); }
найдите процессы, запущенные с одним и тем же путем текущего файла, и верните количество найденных процессов. Затем, если их больше 7, выйдет.
Ответ 4
Использование CRON
#!/bin/sh
process = 'script.php'
if ps ax | grep -v grep | grep $process
then
echo "$process is running..."
else
echo "$process not running, relaunching..."
php /your/php/script.php
fi
Ответ 5
Чтобы дополнить ow3n, PHP CLI script похож на любую другую команду и может быть легко повторен в бесконечном цикле while
. Он будет работать точно так же, как запуск команды сам по себе, но будет работать снова, когда она закончится. Просто нажмите Ctrl + C, когда вы хотите завершить цикл.
Изменить: Если ваш процесс ловит сигналы (что должно быть, если оно 12 факторное приложение), вам нужно будет удерживать Ctrl + C, а не просто нажимать на него. Пресса будет захвачена процессом (который должен завершиться сам), но цикл while
снова перезапустит процесс (что полезно, если вы просто хотите перезапустить процесс, а не прекратить его). Если ваш процесс не захватывает сигналы, то Ctrl + C убьет цикл и цикл while
.
Вот самый простой способ сделать это без дополнительного вывода:
while :; do [command]; done
while :; do echo "test" && sleep 1; done
while :; do php myscript.php; done
Тем не менее, я немного обеспокоен последствиями в ваших комментариях:
О потоках:
- Я бы дважды подумал об использовании потоков в PHP. Языки, использующие эту модель, имеют гораздо лучшую/стабильную/зрелую среду, чем PHP (например, Java).
- Использование нескольких процессов вместо нескольких потоков может показаться неэффективным, но, верьте мне, это больше, чем делает это с точки зрения простоты, ремонтопригодности, легкости отладки и т.д. Многопоточность может быстро привести вас к афиша обслуживания, в котором объясняется появление Модель актера.
- Является ли эффективность бизнес-требованием? Это обычно из-за ограниченных ресурсов (например, встроенных устройств), но я сомневаюсь, что ваш случай, иначе вы бы не использовали PHP. Учтите, что сегодня люди намного дороже компьютеров. Поэтому для минимизации затрат гораздо более выгодно максимизировать эффективность ваших людей, а не ваших компьютеров (см. Философию Unix "Правило экономики" ), Многопоточность, если все будет хорошо, сэкономит вам немного денег, оптимизируя использование ваших компьютеров, но будет стоить вам гораздо больше с точки зрения головных болей, которые это вызовет для ваших людей.
- Если вам абсолютно необходимо использовать потоки, я настоятельно рекомендую вам рассмотреть модель Actor. Akka - отличная реализация.
О процессах:
- Если вы запускаете свои скрипты в процессе разработки, одного процесса [каждого типа] должно быть достаточно.
- Если вы запускаете свои сценарии в процессе производства, вы должны полагаться на диспетчер процессов для управления вашими процессами, такими как Upstart.
- Избегайте превращать ваши процессы в дьямонов.
- Узнайте о 12 факторных приложениях, особенно processes, concurrency и disposability.
Обновление: Контейнеры упрощают работу и управление флотом процессов.
Ответ 6
Чтобы перезапустить script каждый раз, когда он перестает работать, вы можете обернуть user1179181 script в цикле.
#!/bin/bash
while true
do
if ps ax | grep -v grep | grep "script.php"
then
echo "process is running..."
else
clear
date
echo "process not running, relaunching..."
PHP скрипт.php
fi
sleep 10
done
Ответ 7
Только мои 5 центов. Перезапуск PCNTL с пользовательской обработкой ошибок.
register_shutdown_function("shutdownHandler");
function shutdownHandler() //will be called when PHP скрипт ends.
{
$lasterror = error_get_last();
switch ($lasterror['type'])
{
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
case E_PARSE:
$error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
myCustomLogHandler("FATAL EXIT $error\n");
}
$_ = $_SERVER['_'];
global $_;
pcntl_exec($_);
}