exec関数のタイムアウト処理 - PHPプロ!Q&A掲示板

551

  • 0P

exec関数のタイムアウト処理

質問日時 / 2007年6月21日 11:07    回答数 / 7件

Questioner:  potkurin  このエントリーをはてなブックマークに追加 

キーワード / 外部プログラム    実行    タイムアウト   

こんにちは。

現在exec関数を使用して外部プログラムを起動しています。

この外部プログラムが非常に時間のかかるものです。

かかる時間は時と場合によってまちまちだったりします。

そこで、ある一定時間を経過した場合はexec関数で実行した外部プログラムを終了させたいのです。

何かよい方法をご教示いただければ幸いです。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┗A01taktoこんにちは。 PHP5ならproc_open()で開いたプロセス
 ┗A01-1potkurin御返信ありがとうございます。 確かに、失ってはま
  ┣A01-1-1taktoそれは最初の話とずれてくると思いますよ。ちょっと流
  ┃┗A01-1-1-1potkurin御返信ありがとうございます。 最初の説明とずれて
  ┃ ┗A01-1-1-1-1taktoたびたびすいません、最後にひとつだけ。 > これは
  ┗A01-1-2kaitau外部プログラムの処理のハンドリングについてはtakto
   ┗A01-1-2-1potkurin皆様、ご指摘ありがとうございました。 どうやらな

回答一覧

並び替え:

A01
answerertakto [6月21日 11:43] (最終編集:6月21日 11:44)

こんにちは。
PHP5ならproc_open()で開いたプロセスを強制終了させるproc_terminate()という関数があります。
ありますがそんな運用は正直お勧めできない気がします。どんな処理をさせているのかわかりません
が、処理データの内容は強制終了しても問題ないのでしょうか。

どちらかというとバックグラウンドでプロセスを実行させる方法をとってみた方が安全ではないか
と思います。

PHPマニュアルの邦訳より引用します。
> 注意: この関数を用いてプログラムを開始し、バックグラウンドで実行させたままにしたい場合、
> このプログラムの出力をファイルまたは他の出力ストリームにリダイレクトするようにする必要
> があります。さもないと、PHP はプログラム実行終了までにハングしてしまいます。

ということで、例えば
exec("hoge.sh");
であれば
exec("hoge.sh > /dev/null &");
とすればよい、ということです。

状況と仕様によって判断しなければならないと思いますがご参考までに。

この意見に回答する

ツリーへ TOPへ

A01-1
replyerpotkurin [6月21日 11:59]

御返信ありがとうございます。

確かに、失ってはまずいデータなので、強制終了はいけませんでした(汗

御教示いただいたバックグラウンドでの実行ですが、裏でプロセスは走ってるけれども画面はどんどん先へ進むことができることになりますよね。

正常値にしろ異常値にしろ、外部プログラムの処理結果を受け取ってから次画面に処理を進めたいと思っています。

やはりそれは技術的に難しいのでしょうか・・・。

この意見に回答する

ツリーへ TOPへ

A01-1-1 満足
replyertakto [6月21日 12:41]

それは最初の話とずれてくると思いますよ。ちょっと流れを整理しましょう。
罫線がずれませんように…

呼び出し元PHP──┐
         ├->外部プロセス
 次画面処理へ←─┘

必ずこういった外部プロセスの結果が次処理に影響を及ぼす流れにしたいのであれば、呼び出し
たプログラムがいつ値を返すかというところになると思います。例えば適度にブレイクポイント
みたいなものを用意してそのポイント時点でタイムアウトと判断してreturnするとか。
ベタベタなやり方でなんですが下記のような感じです。呼び出し先のプログラムがわからないの
で適当にPHPで書いておきます。
  1. // 処理実行前
  2. $before = time();
  3. $timelimit = 10;  // 例えばタイムアウトを10秒とする
  4.  
  5. // あるまとまった処理
  6.  
  7. $now = time();
  8. //  制限時間を越えていたら強制的に終了させる
  9. if($now - $before > $timelimit){
  10.   // 戻しても大丈夫なような終了処理を書く。
  11.   return false;
  12. }
  13.  
  14. // 次のまとまった処理
  15.  
  16. $now = time();
  17. // 以下略

コード中のコメントに書いたように、この場合でも途中で返してしまって実行途中だった
データをロールバックするような処理がいるかどうか、そういったギミックを考える必要
があるでしょう。呼び出した側が何か制御するようなものではないので、呼び出し先の処
理のパフォーマンスチューニングか、そもそもの処理のフローを洗い直すアプローチを取
る方がよいのではないかと思います。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1
replyerpotkurin [6月21日 13:51]

御返信ありがとうございます。

最初の説明とずれてしまって申し訳ありません。

御指摘の内容は大変よくわかりました。

実は外部モジュールはCで作成したものなので、ご指摘の内容をそのまま利用するわけにはいかなさそうです。

これはもう、外部モジュールの中でタイムアウト処理を行っていないことが問題ということになりそうですね。

がんばってみます。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-1 参考になった
replyertakto [6月21日 15:16]

たびたびすいません、最後にひとつだけ。

> これはもう、外部モジュールの中でタイムアウト処理を行っていないことが問題ということになりそうですね。

と、言い切れるかどうかということです。最初の前提に戻ってみましょう。
potkurinさんは呼び出し先の実行時間が「時と場合によりまちまち」であるとおっしゃいました。
この「時と場合」は呼び出し元であるPHPである程度絞り込めますか?

タイムアウト処理がなくても許せる程度に条件を絞り込めるならそれは呼び出し側で出来る処理
だと思います。例えば引き渡すデータが不定で、長大データのときはその分大変な時間がかかっ
てしまう、といったシチュエーションであれば、長大データを分割もしくは切り出すような形で
処理を進めることが出来るか?というところでなんとかなるかもしれません。
なんとか呼び出し元でチューニングするとしたらそういったあたりだと思います。そこから先は
呼び出し先のチーム?とか担当の方とご相談とかかもですね。頑張ってください。

この意見に回答する

ツリーへ TOPへ

A01-1-2 参考になった
replyerkaitau [6月21日 15:21]

外部プログラムの処理のハンドリングについてはtaktoさんが解説されているので、
Webインターフェイスのアプローチについてアドバイスさせていただきます。

こういった、時間のかかる処理をさせなければいけない、なおかつ出力結果を受け取らなければならない、という場合、間に待機画面を表示させて、その間定期的に出力のステータスを監視する手法が有効かと思います。

定期的に監視するためのひとつの手段として、HTMLタグの
<meta http-equiv="refresh"...
を用いて、自分自身を一定時間ごとに読み込ませる方法があります。

ものすごくざっくりなサンプルで書くと、
  1. <?
  2. //状態の確認
  3. if( file_exists('hoge_result.txt') ) {
  4.   if( filesize('hoge_result.txt') > 0 ) {
  5.     //処理終了。
  6.     //結果を表示する処理をするなり、リダイレクトさせるなりする
  7.     echo "結果:".file_get_contents('hoge_result.txt');
  8.     unlink('hoge_result.txt');
  9.     exit;
  10.   }
  11. } else {
  12.   //外部プログラムの実行
  13.   exec("hoge.sh > hoge_result.txt &");
  14. }
  15. ?>
  16. <html>
  17. <head><meta http-equiv="refresh" content="20"></head>
  18. <body>しばらくおまちください・・・</body>
  19. </html>
みたいなイメージです。(もちろん、状態の確認や結果の判定は工夫をする必要がありますが。)
metaタグの他にも非同期通信などを用いる方法もありますが、本質的には変わりはありません。

この意見に回答する

ツリーへ TOPへ

A01-1-2-1
replyerpotkurin [6月21日 18:26]

皆様、ご指摘ありがとうございました。

どうやらなんとかなりました。

PHPを動作させている環境の、Linuxのコマンドでtimeoutが用意されておりました。

書式は下記のとおりです。

> timeout_[オプション]_タイムアウト時間_実行シェル_実行シェルの引数

execで上記コマンドのような文字列を記述し、30秒後に強制的に終了するようにしました。

いちおう、タイムアウトしたらリトライするような感じで対応しました。(データ量はその都度ランダムでちがうので・・・)

御返信いただきました皆様に感謝いたします。

今後ともよろしくお願いいたします。

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
動的なURLを静的に見せる方法
 このエントリーをはてなブックマークに追加 
A
普通に考えて、mod_rewrite でしょうね。 http://www.nishishi.com/blog/2006/01/mod_rewrite_url.html...

>>続きを読む

GETのままでは検索エンジンのロボットが拾ってくれなかったためにSEO対策として有効だと言われていますね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)