2010-11-24 4 views
6

私は、データベースからデータの塊を取得し、それを処理し、さらにデータがあるかどうかを調べるPHPスクリプトを持っています。このプロセスは無期限に実行され、一度に1つのサーバー上で複数のプロセスを実行します。問題は、いくつかの時間後に、何かが実行を停止するプロセスを引き起こしていると私はそれをデバッグし、原因を特定することができていないPHPスクリプト終了のソースを見つけるベストプラクティス

<?php 
    while($shouldStillRun) 
    { 
     // do stuff 
    } 
    logThatWeExitedLoop(); 
?> 

はそれはのようになります。ここで

は、私がこれまでの情報を取得するために使用しているものです:

  • はerror_logに - すべてのエラーをログが、エラーはエラー・ログに表示されません。
  • register_shutdown_function - カスタムシャットダウン機能を登録しました。これは、プロセスがサーバーによって殺されていないことを知っているので、終了することが許可されているので、呼び出されます。 (あるいは、少なくとも私はこれが呼び出される場合であると仮定?)
  • debug_backtraceは - 私のカスタムシャットダウン機能でdebug_backtrace()をログに記録しました。これは1つのコールしか表示せず、私のカスタムシャットダウン機能です。
  • スクリプトの最後に到達した場合のログ - ループ外では、スクリプトがループを終了したことを記録する機能があります(したがって、通常はソースファイルの最後に到達します)。スクリプトがランダムに死んだときには、これを記録していないので、何が殺されても処理の途中で殺されます。

原因を見つけるために他にどのようなデバッグ方法をお勧めしますか?

注:これは、これらのスクリプトでは無効になっているmax_execution_timeの問題ではありません。殺されるまでの時間は矛盾しています。それは死ぬ前に10秒または12時間実行することができます。


更新/ソリューション:ご提案ありがとうございました。出力を記録することで、MySqlクエリが失敗したときにスクリプトがdie()に設定されていることがわかりました。 D'oh。 mysqlエラーを記録して終了するように更新しました。それは魅力のように今働いている!

+1

http://www.php.net/manual/en/features.connection-handling.phpには、「タイマーが切れると、スクリプトは中止され、上記のクライアントの切断の場合と同様に、シャットダウン機能が有効になっていればそれが登録されると登録されます。あなたのステートメント「これは呼び出されるので、プロセスがサーバーによって強制終了されていないことを知っています」が間違っている可能性があります。 –

+1

あなたが指摘したように、shutdown_backtraceはシャットダウン機能では役に立たないのです。シャットダウン機能には、トリガされたものとは別のコールスタックが存在するからです。 – Piskvor

答えて

2

PHPはiniファイル内に、スクリプトの実行時間を指定する変数があります。 max-execution-time

この問題を解決していないことを確認するか、set_time_limit()を使用して実行時間を延ばしてください。このプログラムは、Webサーバーを介して実行されているか、またはCLI経由で実行されていますか

追加:私の悪いPHP体験。今年初めに書いた背景のスクリプトを見てみましょう。申し訳ありませんが、PHPは長い時間何かをするためのひどいスクリプト言語です。最新のPHP(アップグレードしていない)にGCを強制的に実行させる機能が追加されていることがわかりました。私が抱えていた問題は、あまりに多くのメモリを使用することからです。なぜなら、GCが決して実行されないためです。再帰的に参照するものを使用すると、決して解放されません。

100,000個のアイテムの配列を作成するとメモリーが作成されますが、配列を空の配列に設定するかスプライシングしてすぐに解放せず、未使用としてマークしません(新しい100,000要素配列メモリを増やす)。

私の個人的な解決策は、永遠に走るperlスクリプトと、system( "php my_php.php");必要に応じて通訳者が完全に解放されるようにします。私は現在5.1.6をサポートしていますが、これは5.3以降で修正されるかもしれませんが、GCを強制的にクリーンアップするためのGCコマンドがあります。

簡単なスクリプト

 
#!/usr/bin/perl -w 

use strict; 

while(1) { 
    if(system("php /to/php/script.php") != 0) { 
    sleep(30); 
    } 
} 

、あなたのPHPスクリプト

 
<?php 

// do a single processing block 

if($moreblockstodo) { 
    exit(0); 
} else { 
    // no? then lets sleep for a bit until we get more 
    exit(1); 
} 

?> 
+0

私の注意を参照してください:) - 最大実行時間は問題ではありません。スクリプトは別の起動スクリプトによって開始されます。 このスクリプトは各プロセスを次のように起動します。 exec( 'php /script/to/run.php>/dev/null 2>&1&echo $!'、$ output); (私はそれが後で生きているかどうか追跡できるようにプロセスIDを取得します) –

+1

スクリプトの出力をログファイルに記録しようとしましたか? – Rahly

+1

exec( "php /script/to/run.php /to/log/file.txt 2>&1&echo $!") – Rahly

0

に、私は、各ループのいくつかの異なる場所にあるファイルへの機能の状態を記録するだろう。

var_export($varname,true)フォームを使用して、ほとんどの変数の内容をvar_exportの文字列として取得できます。

これを特定のファイルに記録して、それに気を付けることができます。ログが終了する前の関数の最新の状態は、手がかりを提供するはずです。

0

何が起こっているかのような音は、標準のPHPエラーではありません。 try ... catchステートメントを使用して独自のエラーをスローする必要があります。私はPCから離れて私の電話上にあるので、私はそれ以外の詳細を持っていない。

+0

'try {something();} catch(Exception $ e){trigger_error( 'あなたのエラーテキスト:'。$ e、E_USER_WARNING);}'しかし、try/catchが動作するためには、コードが例外をスローする必要があります。 – JAL

2

スクリプトのメモリ使用量を記録します。たぶん、それはあまりにも多くのメモリを取得し、メモリ制限を突破し、死ぬでしょうか?

0

これまで仕事中のプロジェクトでこれが発生しました。同様の設定 - PHPスクリプトは、実行するタスク(電子メールの送信、レコードの更新、一部のデータの処理など)がある場合にDBをチェックします。 PHPスクリプトの中にwhileループがあり、

while(true) { 
    //do something 
} 

このスクリプトも何とか殺されます。私はすでにmax_execution_timeを設定する、var_exportを使ってすべての出力を記録する、try_catchを置く、スクリプトの出力を作成する(php ...> output.txt)などのように、ここで述べたことのほとんどを試しました。問題が何であるかを調べる。

私はPHPが単なるバックグラウンドタスクを行うために構築されていないと思います。私はそれがあなたの質問(これをデバッグする方法)に答えるのではないことを知っているが、私たちがこれを働かせた方法は、5分ごとにPHPファイルを呼び出すためにcronジョブを使用したということです。これはJeremyのperlスクリプト使用の答えに似ています。実行後にインタプリタがフリーであればそれを保証します。

0

これがLinuxの場合は、システムログを調べてみてください。プロセスはOOM(メモリ不足)のキラーによって殺される可能性があります(まれに、これが起こっていれば他の問題も起こります)。セグメンテーションフォールト(PHPのいくつかのバージョンでは、いくつかのバージョンのエクステンションが気に入らずクラッシュする)

関連する問題