set_time_limit не влияет на PHP-CLI

Как решить set_time_limit, не влияя на PHP-CLI?

#!/usr/bin/php -q <?php set_time_limit(2); sleep(5); // actually, exec() call that takes > 2 seconds echo "it didn't work again"; 

Solutions Collecting From Web of "set_time_limit не влияет на PHP-CLI"

Решением здесь является использование pcntl_fork() . Боюсь, что это только POSIX. PHP необходимо скомпилировать с помощью --enable-pcntl и not --disable-posix . Ваш код должен выглядеть примерно так:

 <?php function done($signo) { // You can do any on-success clean-up here. die('Success!'); } $pid = pcntl_fork(); if (-1 == $pid) { die('Failed! Unable to fork.'); } elseif ($pid > 0) { pcntl_signal(SIGALRM, 'done'); sleep($timeout); posix_kill($pid, SIGKILL); // You can do any on-failure clean-up here. die('Failed! Process timed out and was killed.'); } else { // You can perform whatever time-limited operation you want here. exec($cmd); posix_kill(posix_getppid(), SIGALRM); } ?> 

В основном, это делает fork новый процесс, который запускает блок else { ... } . При успешном завершении мы отправляем сигнал тревоги родительскому процессу, который запускает блок elseif ($pid > 0) { ... } . Этот блок имеет зарегистрированный обработчик сигнала для сигнала тревоги done() обратный вызов done() ), который успешно завершается. Пока это не будет получено, родительский процесс будет спать. Когда тайм-аут sleep() завершен, он отправляет SIGKILL в дочерний процесс (предположительно висящий).

Предел max_execution_time , который задает set_time_limit , подсчитывает (по крайней мере, в Linux) время, затрачиваемое процессом PHP, во время работы.

Цитирование страницы руководства set_time_limit() :

Примечание. Функция set_time_limit() и директива конфигурации max_execution_time влияют только на время выполнения самого скрипта .
Любое время, затрачиваемое на активность, которое происходит вне выполнения сценария, например системные вызовы с использованием system() , потоковые операции, запросы к базе данных и т. Д., Не включается при определении максимального времени выполнения сценария.
Это не относится к Windows, где измеренное время реально.

Когда вы используете sleep() , ваш PHP-скрипт не работает: он просто ждет … Итак, 5 секунд, которые вы ожидаете, не учитываются лимитом max_execution_time .

Не могли бы вы попробовать запустить php через exec и использовать команду «timeout»? (http://packages.ubuntu.com/lucid/timeout)

use: команда timeout [-signal] time.

Я понимаю, что скрипт висит в цикле. Почему бы просто не $STARTUP_TIME=time() начало скрипта, а затем продолжить проверку в цикле, если скрипт перестанет работать?

Очень хаки, но, поскольку я часто использую скрипты cli, я допускаю позорное совпадение с подобным взломом в прошлом. Требуется 2 скрипта.

Ваш первый cron-скрипт (тот, который зависает) регистрирует свое время начала и processid в плоском файле -> функция getmypid будет для вас другом. Второй скрипт, выполняемый cron каждые (x) минуты, проверяет файл flatfile, убивает все, что прошло заодно, время выполнения, очищает файл flatfile и даже журналы в другом файле, если вы хотите.

Удачи 😉

ОБНОВИТЬ:

Вспомнил этот вопрос и вернулся, чтобы опубликовать это. В то время как рывком по счету Github Себастьяна Бергмана я наткнулся на php-invoker . По словам автора:

Класс полезности для вызова PHP-вызовов с таймаутом.

Несмотря на то, что текущий ответ очень хорош для не-портативного использования на базе Linux, если требуется кросс-платформенное решение, это решение должно быть совместимым с окнами, для тех бедных душ, которые работают на ветровом стекле. Г-н Бергманн, будучи богом PHP, я полностью ручаюсь за качество сценария.

ИЗМЕНИТЬ 1

Я заметил этот комментарий в руководстве PHP:

Обратите внимание, что в Linux время сна игнорируется, но под Windows оно считается временем выполнения.

Насколько я понимаю, сон реализуется как системный вызов и поэтому игнорируется PHP, как описано в руководстве .

EDIT 2

там вместо exec () работает exec (). и некоторые exec () вещи зависают бесконечно. Я также пытаюсь убить его из exec (на linux shell), например exec (kill_after15secs myscript.sh), но я не могу найти, что либо

Теперь я вижу реальный вопрос. Предполагая, что вы работаете в среде Lunix / Unix, вы можете разработать решение для этих строк:

 <?php $pid = system( 'sh test.sh >test-out.txt 2>&1 & echo $!' ); ?> 

Угадайте, что это зафиксировало идентификатор процесса начатого вами процесса. Вы можете записать его в базу данных или текстовый файл вместе с меткой времени. В другом скрипте cron, который запускается, скажем, каждые 5 минут, извлекает все идентификаторы процессов, которые были созданы 5 минут назад, и проверьте, все ли они запущены:

 <?php $status = system( 'ps ' . $pid ); ?> 

Если процесс все еще запущен, вы получаете две строки вывода:

  PID TTY STAT TIME COMMAND 2044 ? S 0:29 sh test.sh 

Если это так, прекратите его следующим образом:

 <?php system( 'kill ' . $pid ); ?> 

Я написал статью о создании фоновых процессов в PHP (и затем охоту на них). Оттуда были скопированы все примеры.

ИЗМЕНИТЬ 3

Все точки, соединенные вместе:

 <?php $pid = system( 'sh test.sh >test-out.txt 2>&1 & echo $!' ); $timer = 300; while( --$timer ) { sleep(1); $status = system( 'ps ' . $pid ); $status = explode( "\n", $status, 2 ); // I am not sure, please experiment a bit here if ( count( $status ) == 1 || trim( $status[ 1 ] ) == '' ) { die( 'spawned process ended successfully' ); } } system( 'kill ' . $pid ); die( 'spawned process was terminated' ); ?>