終了したプロセスのPIDがある場合、そのプロセスの戻り状態をどのように知ることができますか?
何がプロセスを終了したのかわからないので、戻り状態が143(kill
)か137()かを具体的に疑問に思います。kill -9
rootアクセス権を持たないサーバーのPHPスクリプトで実行されるPythonスクリプト。 Pythonスクリプトは数分間実行されますが、PHPは30秒に制限されています。 PHPには戻り状態を取得する関数がありますが、exec()
PHPスクリプトがタイムアウトした場合、この関数は機能しません!
答え1
これはphp.ini
(デフォルト)または同等の設定によってほぼ確実に決定されます。
max_execution_time = 30
TLDR:PHPが最初に終了し、何かがスクリプトを終了することが確実であれば、次のことができます。悪魔Pythonプロセスをラップして監視する(再起動しないモード、つまり--respawn
)信号プロセッサPythonスクリプトで。
一般に、スクリプトのユーザーIDでシェルを実行できる場合は、それを処理できる必要があります。strace
たとえばtruss
、Linuxではこれを大幅に効率的に実行できます。
$ sleep 60 &
[1] 10873
$ strace -e trace=signal,process -p $!
Process 10873 attached - interrupt to quit
+++ killed by SIGKILL +++
Process 10873 detached
プロセスsleep
が他の端末によって終了しましたkill -9
。kill -9
ただし、プロセスはこれをキャッチしてきちんと終了できないため、これは一般的ではありません。
daemon
次のバリアントを使用して監視するには:
daemon -i --errlog=/tmp/mypy.log -- /usr/bin/python [...]
終了関連信号はすべて記録されます。とにかくすべてのシャットダウンを記録するには、--dbglog
およびを追加します。--debug=2
他のところで述べたように、プロセスが終了すると消えます。親(またはinit)だけが終了コードを取得でき、記録されていないと(おそらくプロセスアカウントまたは監査を使用して)失われます。
* nixプラットフォームの内部タイムアウト処理のために、PHPはタイムアウトSIGALARM
またはSIGPROF
指定されたタイムアウトを設定します。シグナルハンドラは単に内部zend_error()
関数を呼び出します。しかし、これもコールバック登録そしてエラーハンドラ、これは役に立つかもしれません。
デフォルトのエラーハンドラが起動すると、タイムアウトがE_ERROR
。
また、終了コードが 128+N(ここで N はシグナル番号)となるルールは、bash
一部のシェル(含む)や多くの API の動作によるものです。信号の後の実際のプロセス終了コードは、システムによって異なります。これはおそらく通常、Linuxの場合のシグナル番号だけが必要です。このwait()
システムコールセットは、プロセスの終了に関するより良い詳細を提供します。 PHPはシェルの規則に従います。たとえば、PHPを使用している場合、popen()
信号pclose()
がプロセスを終了すると終了コードとして128 + Nが表示されます。
ここでの別の考慮事項は、PHPタイムアウトの動作です。set_time_limit()
あなたが見ることができる文書
set_time_limit() 関数と構成ディレクティブは、
max_execution_time
スクリプト自体の実行時間にのみ影響します。system()
スクリプトが実行できる最大時間を決定するときに使用されるシステム呼び出し、ストリーム操作、データベースクエリなど、スクリプトの実行外で発生するすべてのアクティビティに費やされた時間は含まれません。測定された時間は実際なので、Windowsではそうではありません。
短いスクリプトを使用してこれを実演できます。
<?php
# for (;;);
$exe="sleep 20";
print "exit code: " . pclose(popen($exe, 'r'));
?>
として呼び出すと、time php -d max_execution_time=5 -f sleep3.php
スクリプトはエラーなしで20秒間実行されます。たとえば、他の端末で省電力プロセスを終了すると、kill -USR1 $(pgrep sleep)
終了コード138(128 + SIGUSR1)が表示されます。
無限ループのコメントを外すと、for(;;)
5秒後にスクリプトが終了します。
答え2
終了したプロセスがシステムに存在しなくなりました。実際には、忙しいホストでは、終了した長期実行プロセスのPIDが他のプロセスで再利用される可能性が高いので、最終的に完全に関連していないことがわかります!
プロセスが終了すると、それ何も返しません。もう存在しません。これは、処理するHUP又はUSR1のような捕捉可能な信号とは対照的である。できる(必ずしもそうではありませんが)適切であると判断される方法でキャプチャおよび処理されます(定義された終了コードで終了を含む)。
アクセス権が十分な場合は、システムコールを傍受して記録し、最終的には関連プロセスがシグナルを受け取るようにするライブラリやカーネルモジュールをインストールすることができますが、簡単に見えます。pjc50が提案したとおりただラッパースクリプトの追加そしてどこかに終了ステータスを記録します。
別のオプションは、ユーザーを待つのではなく、ユーザーを待つようにすることです。非同期アーキテクチャに切り替える何をしても完了するには長い時間がかかります。
答え3
欲しい待機プロセス()しかし、PHPで利用可能かどうかはわかりません。ブロックしたくない場合は、WNOHANGを追加することを忘れないでください。ただし、これはPIDが呼び出しプロセスの子である場合にのみ機能します。
最も簡単な方法は、おそらくログファイルのどこかに終了状態を記録するPythonスクリプトの周りにラッパースクリプトを配置することです。
答え4
別のオプション:
PHPから:
exec("./wrapper.sh");
存在するwrapper.sh
:
#!/bin/bash
./wrapperlogger.sh >/dev/null 2>&1 &
存在するwrapperlogger.sh
:
./yourPythonScript
echo $? > exit_status.log
最初のラッパーはプロセスのバックエンドです。 2番目のラッパーは終了コードを監視し、それをファイルに書き込みます。このスクリプトは、実行されるたびに同じログファイルを上書きします。