веб-сервисы Amazon — ограничение времени для popen / fgets в Stack Overflow

Я хочу наложить ограничение на время чтения процесса с использованием fgets, открываемых popen в 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
    формат событий.
  2. Запрос получен AWS Load Balancer и является
    перенаправлено в инстансы EC2.
  3. Ответ — последние 30 строк файла
  4. Браузер получает его в 30 сообщениях, и соединение сохраняется.
  5. Если команда tail отправляет новую строку, она возвращается, иначе fgets ожидает неопределенное время, пока новая строка не будет возвращена из команды tail.
  6. AWS Load Balancer через 60 секунд бездействия сети (нет новых строк через 60 секунд) закрывает соединение с браузером. Соединение с экземпляром EC2 не закрыто.
  7. Браузер обнаруживает, что соединение закрыто, и открывает новое соединение, процесс возвращается к шагу 1.

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

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

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

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

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

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

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

3

Решение

Протестировано с 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

Другие решения

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

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

Вы можете настроить тайм-ауты stream и stream_select.

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

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') чтобы получить пид и убить его system("kill $pid")

kill.php

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

echo system('ps auxww');
0

По вопросам рекламы [email protected]