私も一度関連する問題がありました。説明させてください。ダウンローダーのように機能するphp「デーモン」がありました。定期的にフィードにアクセスし、ネットからコンテンツをダウンロード(laaaarge)します。デーモンは特定の時間に停止する必要がありました。たとえば、日中に帯域幅全体を使用しないようにするために、午前0500としましょう。cronjobを使用して、0500のデーモンにSIGTERMを送信することにしました。
デーモンには、次のコードがあります。
pcntl_signal(SIGTERM, array($this, 'signal_handler'));
signal_handler
このように見えた場所:
public function signal_handler($signal) {
// some cleanup code
exit(1);
}
残念ながら、これは機能しませんでした:|
何が起こっているのかを知るのに時間がかかりました。私が最初に理解したのは、pcntl_signal_dispatch()
シグナルディスパッチを有効にするには、initでメソッドを呼び出す必要があるということでした。ドキュメントからの引用(コメント):
PHPをCLIおよび「デーモン」として(つまりループ内で)実行している場合は、この関数を各ループで呼び出して、新しいシグナルがディスパッチを待機しているかどうかを確認する必要があります。
さて、これまでのところ、それは機能しているように見えました。しかし、特定の条件下では、これでも期待どおりに機能しないことにすぐに気付きました。以前のように、デーモンはkill -9
-によってのみ停止できる場合がありました。:|
では、何が問題なのですか?..回答:私のプログラムはwget
、を介してファイルをダウンロードするために呼び出されましたshell_exec
。問題は、shell_exec()
子プロセスが終了するまでブロッキングが待機することです。このブロッキング待機中は信号処理は行われず、プロセスはSIGKILLを使用してのみ終了できます。これは難しいことです。また、子プロセスは、父親を殺した後にゾンビプロセスになったため、1つずつ終了する必要があるという問題もありました。
これに対する私の解決策は、非ブロッキングIOの出力でのproc_open()
使用とを使用して子プロセスを実行することでした。stream_select()
今ではそれは魅力のように機能します。:)さらに情報が必要な場合は、コメントをドロップすることを躊躇しないでください。
注PHP<5.3を使用している場合は、`を使用する必要があります
declare(ticks=1);
の代わりにpcntl_signal_dispatch()
。そのためのドキュメントを参照できますpcntl_signal()
。ただし、可能であれば、PHP>=5.3にアップグレードする必要があります