PHPで致命的なエラーを処理する方法

このトピックで説明したプロジェクトの1つ(社会系図ネットワーク )では、memkeshに実装された保留中のイベントのキューを使用します。 そのアーキテクチャは次のとおりです。アプリケーションは、さまざまなイベントとそれらに関連するデータ(イベントの種類、受信パラメーター、およびこのイベントの関数ハンドラー)をこのキューに書き込みます。 その後、キューマネージャはこのキューを解析し、保留中のイベントを実行します。 特に、このようなキューは統計の収集に使用されますが、実行にとってより重要な他のタスクにも使用されます。

したがって、キューマネージャの高可用性を確保することは非常に重要です。



しかし、以来 キューハンドラーが外部から来た場合、このイベントハンドラーの品質、つまり ハンドラーが突然エラーをスローした場合、それを処理し、キューマネージャーの作業を続行する必要があります。 しかし、ハンドラーが致命的なエラー(致命的なエラー)をスローすることがあり、これが問題になることがあります...







プロセス(デーモン)を追跡するには、 monitなどのプロセスオブザーバを使用すると非常に便利です。monitを使用してシステムデーモンを監視します。 ところで、最近、habrにmonitに関する記事がありました。

しかし、それは彼についてではありません:-)



チームの開発者の1人に、キューマネージャーコードで通常の致命的なエラーハンドラー、つまりハンドラーの新しいインスタンスのフォークとイベントタイプごとのエラーログを作成するように依頼しました。 これに対して、私は原則として致命的なエラーを処理することは不可能であり、それについて知らないことは恥ずかしいという答えを受け取りました:



その後、致命的なエラーを処理するコードと、PHPアプリケーションの他のすべてのエラーを記述しました。 彼が他の誰かを助けるなら、私はただうれしいです。



<?php



ini_set( "display_errors" , "on" );

error_reporting(E_ALL);

ini_set( 'html_errors' , 'on' );



function fatal_error_handler($buffer) {

if (preg_match( "|(Fatal error</b>:)(.+)(<br)|" , $buffer, $regs) ) {

//

file_put_contents( "php://stderr" , "before fork (pid: " . getmypid() . ")\n" );

system( "php tester.php " . getmypid() . " &" );

return "ERROR CAUGHT, check log file" ;

}

return $buffer;

}



function handle_error ($errno, $errstr, $errfile, $errline)

{

if ($errno & E_ALL){

// -

//switch ,

switch ($errno) {

case E_USER_ERROR:

case E_USER_WARNING:

case E_USER_NOTICE:

default :

//do something

break ;

}

ob_end_clean();

echo "CAUGHT OTHER THAN FATAL ERRORS!!! " . $errstr;

exit;

}

}



//code between ob_start and ob_end_flush is included by MQ Handler, so we know nothing about it, and this code could fire a Fatal Error

if (isset($_SERVER[ "argv" ][1])){

file_put_contents( "php://stderr" , "kill {$_SERVER['argv'][1]}: " .var_export(posix_kill($_SERVER[ 'argv' ][1], 15), true ). "\n" );

}

ob_start( "fatal_error_handler" );

set_error_handler( "handle_error" );



while ( true ) {

//Just a Warning

//$a = 9/0;

sleep(10);

file_put_contents( "php://stderr" , "live\n" );

//Fatal error - -

if (rand(1,10) % 2 == 1) {

ololo(123);

}

}



/*



*/

$a = rand(1,10);

echo $a. "<br/>" ;



ob_end_flush();



echo "Program still executing...." ;



?>




* This source code was highlighted with Source Code Highlighter .






現在のコードに関する簡単な説明。

致命的エラー-fatal_error_handlerの出力バッファリングを通じてキャッチします

その他のエラー(致命的を除くすべて)は、handle_errorによって処理されます

エラーがない場合、コードは正常に実行されます:-)



はい、高可用性とフォールトトレランスの唯一の手段ではありません。

クラウンで毎分デーモンを起動しようとすると、デーモンコードが開始されます



<?php



if (!checkSingleProcess()) {

exit;

}



function checkSingleProcess() {

$res = exec( 'ps aux | grep mq_manager.php | grep -v grep | grep -v ' .getmypid(), $output, $ return );

return $output == array();

}




* This source code was highlighted with Source Code Highlighter .








つまり デーモンが実行されている場合、実行を停止します。



私はすべての意見を受け入れ、可能であればすべてのコメントに回答します。



UPD: ini_set( 'html_errors'、 'on')に注意してください。 CLIからハンドラーが機能しない理由を理解せずに30分を費やしました。 それはちょうどHTMLエラーについてでした。 なぜなら CLIからHTMLタグなしで指定され、preg_match( "|(致命的なエラー:)(。+)(<br)|"、$ buffer、$ regs)条件は単に保持されませんでした。 //このように。



UUPD:コードを少し更新しました。実際、f-juシステムを介して分岐した新しいプロセスは、現在のプロセスを分岐したプロセスを強制終了するために処理する必要があります。 ハンドラー関数は、システム関数の実行結果を待ちますが、デーモンを作成しているため、確実に戻りません。これに関連して、メモリーにハングアップするプロセスの束を取得し、最終的にそれを完全に詰まらせます。



All Articles