Как решить 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";
Как решить 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";
Решение здесь - использовать pcntl_fork()
. Я боюсь, что это только POSIX. PHP необходимо скомпилировать с помощью --enable-pcntl
, а не --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()
), который успешно завершается. Пока это не будет получено, родительский процесс будет спать. Когда тайм-аут sleep()
завершен, он отправляет SIGKILL
дочернему процессу (предположительно висевшего).
Ограничение max_execution_time
, что означает set_time_limit
устанавливает, считает (по крайней мере, в Linux) время, затраченное на процесс PHP, при работе.
Указание страницы руководства set_time_limit()
:
Примечание: Функция
set_time_limit()
и конфигурация директиваmax_execution_time
влияют на время выполнения script.
Любое время, проведенное на деятельности, которая происходит вне выполнение script, например системы звонки с использованиемsystem()
, потока операции, запросы к базе данных и т.д. не включаются при определении максимальное время, в течение которого scriptБег.
Это не верно для Windows, где измеренное время реальный.
Когда вы используете sleep()
, ваш PHP скрипт не работает: он просто ждет... Итак, 5 секунд, которые вы ожидаете, не принимаются во внимание пределом max_execution_time
.
Не могли бы вы попробовать запустить php через exec и использовать команду "timeout"? (Http://packages.ubuntu.com/lucid/timeout)
использование: команда timeout [-signal] time.
Очень хакерский, но так как я часто использую скрипты cli, я допускаю позорное совпадение с подобным взломом в прошлом. Требуется 2 скрипта.
Ваш первый cron script (тот, который зависает) регистрирует свое время запуска и processid в плоском файле → функция getmypid будет для вас другом. Второй script, выполняемый cron каждые (x) минуты, проверяет файл flatfile, убивает все, что прошло заостановленное время выполнения, удаляет файл flatfile и даже журналы в другом файле, если вы хотите.
Удачи;)
UPDATE:
Вспомнил этот вопрос и вернулся, чтобы опубликовать это. В то время как рывком через учетную запись github Себастьяна Бергмана я наткнулся на php-invoker. По словам автора:
Класс полезности для вызова PHP-вызовов с тайм-аутом.
Несмотря на то, что текущий ответ очень хорош для использования в портативном режиме на основе Linux, если требуется кросс-платформенное решение, это решение должно быть совместимым с окнами, для тех бедных душ, которые работают на ветровом стекле. Г-н Бергманн, будучи богом PHP, я полностью ручаюсь за качество script.
Я понимаю, что script висит в цикле somehoere. Почему бы просто не запустить $STARTUP_TIME=time()
запуск script, а затем продолжить проверку в цикле, если script needs выйти?
Я заметил этот комментарий в руководстве по PHP:
Обратите внимание, что под Linux время сна игнорируется, но под Windows считается временем выполнения.
Насколько я понимаю, сон реализован как системный вызов и поэтому игнорируется PHP , как описано в руководстве.
вместо exec() работает спать() там. и некоторые вещи exec() висит бесконечно. я также в поисках убийства изнутри exec (на оболочке Linux), как 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 (и выследил их потом). Все примеры были скопированы оттуда.
Все точки соединены вместе:
<?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' );
?>