Подтвердить что ты не робот

Автоматически перезагружать PHP скрипт на выходе

Есть ли способ автоматически перезапустить PHP script всякий раз, когда он выходит, независимо от того, был ли он выполнен правильно или завершен из-за ошибки или максимального использования памяти и т.д.?

4b9b3361

Ответ 1

PHP Script также может перезапустить себя с помощью PCNTL.

Отказ от ответственности: точка этого упражнения заключается только в том, чтобы доказать, что PHP вполне способен перезапустить себя и ответить на вопрос:

Есть ли способ автоматически перезапустить PHP Script всякий раз, когда он выходит, независимо от того, был ли он завершен должным образом или завершился из-за ошибки?

Именно поэтому мы можем подробно рассказать о процессах unix, поэтому я предлагаю вам начать с PCNTL book или обратиться к для получения более подробной информации.

В примерах мы предположим, что это 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($_);
}