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";

Ответ 1

Решение здесь - использовать 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 дочернему процессу (предположительно висевшего).

Ответ 2

Ограничение 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.

Ответ 3

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

использование: команда timeout [-signal] time.

Ответ 4

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

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

Удачи;)

UPDATE:

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

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

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

Ответ 5

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

Ответ 6

ОБНОВЛЕНИЕ 1

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

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

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

ОБНОВЛЕНИЕ 2

вместо 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 (и выследил их потом). Все примеры были скопированы оттуда.

ОБНОВЛЕНИЕ 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' );
?>