Net::Server その2(長い処理をしたい)

前回(http://d.hatena.ne.jp/dayflower/20060908/1157706291)の続きです。やろうと思っていることは,

  1. クライアントからサーバにつなぐ
  2. なんらかのコマンドを与えると処理を行う
  3. 処理には時間がかかるのでトークンだけ返す
  4. あとでそのトークンを元にステータスなどを得られる

といったクラサバです。前回までに 1. と 2. の一部をやりました(コマンドを与えるというより接続しただけですが)。で,今日やりたいのは 3. のあたりの一部です。
時間がかかる処理ということで sleep をかましてみます。前回の process_request のとこで,

sub process_request {
  my ($self) = @_;

  warn 'accepted';

  eval {
    my ($in, $out, $err);
    
    IPC::Run::run(
      [qw( /bin/date )],
      \$in, \$out, \$err,
      IPC::Run::timeout(10)
    )
      or die $?;
    
    print STDOUT $out, "\n";
  };
  croak $@ if $@;
  
  sleep 5;
  
  warn 'bye bye';
}

croak 〜 warn の間に sleep をいれる。するとクライアントから接続すると 5 秒後に日付を出して終了します(当たり前)。そうではなくて,クライアントから接続してすぐに終了して欲しいのです。

では,ソケットを close するとクライアントはすぐに終了してくれるのか。

  ...(略)...

  close *STDIN;
  close *STDOUT;
  
  sleep 5;
  
  warn 'bye bye';
}

と変えて接続してみましたが,駄目(日付がでて5秒後に接続が切れる)。fork して子プロセスに分離してみたりしましたがやはり駄目でした。

Net::Server の sub post_process_request をみてみると,STDIN 等を close した後に $self->{server}->{client} なるハンドルを close しています。こちらがソケット本体でしたか。

このハンドルをじかに触るのもなんなので,考え方を変えて,

sub process_request {
  前回と同じ
}

sub post_process_request {
  my $self = shift;

  $self->SUPER::post_process_request;
  
  sleep 5;

  warn 'bye bye';
}

post_process_request をオーバーライドして解決してみました。

すると見事に client から接続するとすぐにコネクションが切れ,5 秒後にサーバログに「bye bye」と出力されました。

本当はこのままでは駄目なのです。Net::Server の run_client_connection を見るとわかりますが,allow_deny によって deny だった場合にも最後に post_process_request に至るのでよろしくないのです。でもこれでとりあえず道筋は立ちました,ということで。


(ここまで書いておきながら,fork して子プロセスの先頭で $self->post_process_request を呼び,最後に exit を呼ぶほうが本筋な気がしてきました)