3

スーパーバイザー (http://supervisord.org/) を使用して、かなり標準的な PHP スクリプトをデーモン化しています。スクリプトは次のような構造になっています。

while (1) {
//  Do a SQL select
//  for any matching rows, do something
//  if I have been running for longer than 60 mins, exit
}

今日、このスクリプト (かなり安定しています) がハングしました。これは、supervisord にプロセスを再起動するように警告するようなクラッシュ (つまり、SIGHUP または SIGTERM シグナルの発行) はしませんでした。処理中にエラーは発生しませんでした。これは、スクリプトによってキャッチされるか、少なくとも致命的なエラーをトリガーして終了した可能性があります。これらの「キャッチ可能な」シナリオの代わりに、それはただそこに座っていました. PHP スクリプトはメモリの観点からリークが多く、実行時間が長い場合は再起動するのが適切であることが一般的に認められているため、supervisorctl フックを介してスクリプトを再起動するために 1 時間ごとに実行する cron ジョブをセットアップしています。その再起動後、スクリプトは正常に動作を再開しました。

私の質問: このスクリプトがハングしたことをどのように検出できますか? なんらかの方法でその状態を警告されない限り、なぜハングしたのかというこの問題の診断やトラブルシューティングを開始することさえできません。これに対するソフトウェア ソリューション、または自分でソリューションを作成するためのアプローチ (PHP、Python、perl、またはシェルのいずれか) を探しています。

スクリプトは PHP 5.2.6 で書かれており、最新の RHEL 5 サーバーで実行されます。

より素晴らしいソリューションに役立つ場合は、追加情報を共有できるかどうかお知らせください。

ありがとうございました!

シャヒーブ R.

4

3 に答える 3

2

これはスクリプトがハングしているケースであるため、PHP はこのハングを検出できる追加のコードを処理しない可能性があります。このため、ログを保持するようにスクリプトを変更することをお勧めします。これにより、メイン スクリプトはそれがまだ実行中であることを外部に知らせることができます。適切に配置された更新によって、問題が発生した場所を特定するのにも役立ちます。

ログはファイルまたはデータベースに書き込むことができ、少なくとも最終変更日などのスクリプトのステータスのインジケータを含める必要があります。このスクリプトが常に実行されていない場合は、何かが実行中または停止していることも示しているはずです。あなたが示した例では、ログの書き込みはwhileループ内で少なくとも1回、おそらく複数回発生します。ポインターまたは DB 接続を開くには時間/リソースがかかるため、必要なものだけをログに記録することをお勧めします。(注: テキスト ファイル アプローチを使用する場合は、各書き込みの直後にファイルを閉じる必要があります。)

例:

while (1) {
    log('Running SQL select');
    //  Do a SQL select
    log('Results retrieved');
    //  for any matching rows, do something
    //  (check log) if I have been running for longer than 60 mins, exit
}

function log($msg) {
    // Write timestamp, $msg to log
}

別のスクリプトでログを確認し、エラーを報告する必要があります。これは、メイン スクリプトがハングする原因の影響を受けている場合に問題になる可能性がありますが、別の方法は考えられません。

メモリに関しては、まだmysql_free_resultを使用していない場合は、試してみてください。

于 2011-08-26T04:46:19.073 に答える
1

私の提案は@Shroderが説明したものと似ていますが、もう少し進んでいます。実行ごとに log/db エントリを作成し、タイムスタンプ + トランザクションを認識します (実行の開始時にトランザクションを に更新し、processing完了したら、 completed.

一方では、単純な cron チェックを実行し、タイムスタンプとトランザクション状態を使用して、現在の時間がトリガー (60 分など) よりも大きいかどうかを確認します。その時点で、アラートなどをスローします。

于 2011-08-26T05:02:57.077 に答える
0

とても簡単です!ループの開始から現在の実行ポイントまでの時間差を計算するだけです。

$starttime = microtime(true);
while (1) 
{
    //Do your stuff here
    //More SQL, whatever you need


    //Put this at the end of the loop
    $curtime = microtime(true);
    $timetaken = $curtime - $starttime;
    if($timetaken > (60 * 60))
    {
        break;
    }
}

microtime(true)Unixエポックからの秒数を返すため、現在の時間から開始時間を差し引くと、所要時間/経過時間を取得し、60*60秒を超えている場合はループを終了します.

于 2011-08-25T23:07:19.027 に答える