3

PHPのpopenで開いたfgetsを使ったプロセス読み込みに時間制限をつけたい。

私は次のコードを持っています:

$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. ブラウザーは、HTML5 サーバー側イベント形式で応答を待機する GET 要求を送信します。
  2. リクエストは AWS Load Balancer によって受信され、EC2 インスタンスに転送されます。
  3. 答えはファイルの最後の 30 行です
  4. ブラウザは 30 メッセージで受信し、接続は維持されます。
  5. tail コマンドが新しい行を送信した場合、それが返されます。それ以外の場合、fgets は、tail コマンドから新しい行が返されるまで未定義の時間待機します。
  6. 60 秒間ネットワークが非アクティブになった後 (60 秒間新しい行がない)、AWS Load Balancer はブラウザへの接続を閉じます。EC2 インスタンスへの接続が閉じられていません。
  7. ブラウザーは接続が閉じられたことを検出し、新しい接続を開きます。プロセスはステップ 1 に戻ります。

この手順で説明されているように、AWS ロード バランサーと EC2 インスタンス間の接続は決して閉じられません。数時間または数日後に、何百ものテール プロセスと httpd プロセスが実行され、サーバーが応答しなくなります。

もちろん、これは AWS Load Balancer のバグのようですが、プロセスを開始して Amazon の注意を引き、修正を待つ必要はありません。

私の一時的な解決策は、サーバーが不安定になる前にプロセスを強制終了するために sudo kill tail を実行することです。

fgets が終了するのを待って PHP が「ブロック」されているため、PHP はスクリプトを停止しないと思います。

AWS Load Balancer の時間制限が編集可能であることは知っていますが、デフォルト値のままにしておきたいです。制限を高くしても問題は解決しません。

質問を時間制限/タイムアウトでLinuxでプロセスを実行する方法に変更する必要があるかどうかわかりません。

PHP 5.5.22 / Apache 2.4 / Linux カーネル 3.14.35-28.38.amzn1.x86_64

4

2 に答える 2

0

プロセス ファイル ポインターを使用するのではなく、「マルチタスク」アプローチを採用しました。このコードを使用して、他の「プロセス」を生成します。一種のマルチタスク チートです。

90 秒間ハングするだけのスクリプト hang.php を呼び出します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')、pidを取得して強制終了するために使用しますsystem("kill $pid")

kill.php

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

echo system('ps auxww');
于 2015-05-14T14:55:28.560 に答える
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);
于 2015-05-14T04:25:24.453 に答える