forkでCGIの重い処理

back
CGIから重い(処理に時間のかかる)処理を行うと、プログラムが終了するまで
ブラウザにはまったく表示が行われない。場合によってはタイムアウトや
Internal Server Error になる(かもしんない)。



そこで、fork をつかって、親プロセスではすぐにブラウザへ表示を返し終了し、
子プロセスで重たい処理を行う。


----
#!/usr/bin/perl

if($pid = fork) {
  # 親プロセス
  print "Content-type: text/plain\n\n";
  print "done\n";
  close(STDOUT);
  exit;
}
else {
  # 子プロセス
  close STDOUT;
  #
  # この辺に重い処理
  #
  exit 0;
}
----

欠点は、クライアントからプログラムの終了がわからないこと。。。

そこで、fork の*後*に(というか、子プロセスで)ロックファイルを flock し、
プログラム終了にアンロックするようにし、親プロセスでは Location や 
クライアントプルを使ってflock されたロックファイルを監視するプログラムへ
リダイレクトさせる。
※ その際、子プロセスが確実にロックできるように、sleep(1くらい) を入れる。

リダイレクト先では数秒毎に自分自身をロード(というかリンク)させ、そのたびに
ロックファイルが flock でロックされているかどうかをチェックし、
ロック解除(ロック取得成功) -> 重い処理のの結果を表示するページへジャンプ
ロック中(ロック取得失敗) -> x秒後に、再度自分へジャンプ
つー、処理にする。多分。
fork の後に flock するのは、前だと(親プロセスで flock すると)うまくいかないため
ファイルハンドルが子プロセスにもコピーされるとかそーいうことかな?(ソーゾー)

ちなみに Apache 1.3x はうまくいくけど、2.0x はプロセスツリー全体を見ているせいか、
親プロセスからのリダイレクトがうまくいかない。
そこで http ヘッダ
----
Connection: close
----
を出力して、Keep-Alive を切ってやるとうまくいく(みたい)

back