2015-05-14 8 views
3

Я хочу наложить ограничение времени на чтение процесса с использованием fgets, открытых popen в PHP.Укажите временные ограничения для popen/fgets в PHP

У меня есть следующий код:

$handle = popen("tail -F -n 30 /tmp/pushlog.txt 2>&1", "r"); 
while(!feof($handle)) { 
    $buffer = fgets($handle); 
    echo "data: ".$buffer."\n"; 
    @ob_flush(); 
    flush(); 
} 
pclose($handle); 

Я пытался без успеха:

set_time_limit(60); 
ignore_user_abort(false); 

Процесс выглядит следующим образом:

  1. браузер отправить запрос GET ОЖИДАНИИ Ответ в формате HTML5 Server формат событий.
  2. Запрос принимается балансировщиком нагрузки AWS и составляет , отправленный в экземпляры EC2.
  3. Ответ на последние 30 строк файла
  4. Браузер принимает его в 30 сообщениях, и соединение сохраняется.
  5. Если команда tail отправляет новую строку, возвращается иначе. Fgets ожидает неопределенное время, пока новая строка не будет возвращена из команды tail.
  6. Балансировщик нагрузки AWS после 60 секунд бездействия сети (без новых линий за 60 секунд) закрывает соединение с браузером. Соединение с экземпляром EC2 не закрыто.
  7. браузер обнаруживает, что соединение закрывается и открывается новое соединение, процесс возврата к шагу 1.

AS это шаги описывают связь между AWS балансировки нагрузки и экземпляра EC2 никогда не закрывается, через несколько часов/дней выполняется сотни и сотни процессов хвоста и httpd, и сервер не отвечает.

Конечно, это ошибка AWS Load Balancer, но я не хочу начинать процесс, чтобы привлечь внимание от Amazon и ждать исправления.

Моим временным решением является удаление хвоста sudo kill, чтобы убить процесс до того, как сервер станет нестабильным.

Я думаю, что PHP не останавливает сценарий, потому что PHP «заблокирован», ожидая окончания работы fgets.

Я знаю, что ограничение срока службы балансировщика нагрузки AWS редактируется, но я хочу сохранить значение по умолчанию, даже более высокий предел не поможет устранить проблему.

Не знаю, нужно ли мне изменить вопрос о том, как выполнить процесс в Linux с ограничением по времени/тайм-ауту ?.

PHP 5.5.22/Apache 2.4/Linux Kernel 3.14.35-28.38.amzn1.x86_64

ответ

0

Испытано с PHP 5.5.20:

//Change configuration. 
set_time_limit(0); 
ignore_user_abort(true); 

//Open pipe & set non-blocking mode. 
$descriptors = array(0 => array('file', '/dev/null', 'r'), 
         1 => array('pipe', 'w'), 
         2 => array('file', '/dev/null', 'w')); 
$process  = proc_open('exec tail -F -n 30 /tmp/pushlog.txt 2>&1', 
           $descriptors, $pipes, NULL, NULL) or exit; 
$stream  = $pipes[1]; 
stream_set_blocking($stream, 0); 

//Call stream_select with a 10 second timeout. 
$read = array($stream); $write = NULL; $except = NULL; 
while (!feof($stream) && !connection_aborted() 
     && stream_select($read, $write, $except, 10)) { 

    //Print out all the lines we can. 
    while (($buffer = fgets($stream)) !== FALSE) { 
     echo 'data: ' . $buffer . "\n"; 
     @ob_flush(); 
     flush(); 
    } 

} 

//Clean up. 
fclose($stream); 
$status = proc_get_status($process); 
if ($status !== FALSE && $status['running'] === TRUE) 
    proc_terminate($process); 
proc_close($process); 
+0

Это лучшее, что я мог бы сделать без использования любые расширения. Это не здорово. Вы по-прежнему можете оставить сиротские процессы, если сбой PHP или Apache. Кроме того, вы можете использовать 'SIGKILL' для' proc_terminate'. –

0

Вместо того чтобы использовать файловый указатель процесса, я пошел с моим «многозадачным» подходом. Я использую этот код, чтобы порождать другие «процессы». Тип многозадачного обмана.

Я вызываю скрипт, hang.php, который просто висит в течение 90 секунд: sleep(90).

Возможно, вы захотите отрегулировать тайм-ауты потока и stream_select.

Создать поток (s)

header('Content-Type: text/plain; charset=utf-8'); 
$timeout = 20; 
$result = array(); 
$sockets = array(); 
$buffer_size = 8192; 
$id = 0; 
$stream = stream_socket_client("ispeedlink.com:80", $errno,$errstr, $timeout, 
    STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); 
if ($stream) { 
    $sockets[$id++] = $stream; // supports multiple sockets 
    $http = "GET /testbed/hang.php HTTP/1.0\r\nHost: ispeedlink.com\r\n\r\n"; 
    fwrite($stream, $http); 
} 
else { 
    echo "$id Failed\n"; 
} 

Дополнительные сценарии могут выполняться путем добавления потока: $sockets[$id++] = $stream;


Ниже будет положить что-нибудь читать в к $result[$id] массива.

Контролировать потоки:

while (count($sockets)) { 
    $read = $sockets; 
    stream_select($read, $write = NULL, $except = NULL, $timeout); 
    if (count($read)) { 
    foreach ($read as $r) { 
     $id = array_search($r, $sockets); 
     $data = fread($r, $buffer_size); 
     if (strlen($data) == 0) { // either reads data or EOF 
     echo "$id Closed: " . date('h:i:s') . "\n\n\n"; 
     fclose($r); 
     unset($sockets[$id]); 
     } 
     else { 
     $result[$id] .= $data; 
     } 
    } 
    } 
    else { 
    echo 'Timeout: ' . date('h:i:s') . "\n\n\n"; 
    break; 
    } 
} 
echo system('ps auxww'); 

.


Когда я хочу, чтобы убить процесс, я использую system('ps auxww'), чтобы получить PID и убить его с system("kill $pid")

kill.php

header('Content-Type: text/plain; charset=utf-8'); 
//system('kill 220613'); 

echo system('ps auxww');