Catalyst の開発版の Helper

PowerBook にインストールして使ってる Catalyst は 5.33 なんだけど、このところすごい勢いでバージョンアップしているらしい。

それはさておき、svn から開発版のソースを拾ってきて Catalyst::Helper のコードを眺めていたら server.pl がずいぶんパワーアップしていることに気づく。

 Options:
   -d -debug          force debug mode
   -f -fork           handle each request in a new process
                      (defaults to false)
   -? -help           display this help and exits
      -host           host (defaults to all)
   -p -port           port (defaults to 3000)
   -k -keepalive      enable keep-alive connections
   -r -restart        restart when files got modified
                      (defaults to false)
   -rd -restartdelay  delay between file checks
   -rr -restartregex  regex match files that trigger
                      a restart when modified
                      (defaults to '?.yml$|?.yaml$|?.pm$')

-r で restart したりできるというのは前にちょっと聞いたけど、fork できるようになってたり keepalive を ON/OFF できたり、あと -rd とか -rr とかオプションが増えてる。

あと、Helper の末尾の方にバイナリの hex dump がw $helper->_mk_imagesCatalyst のロゴとかバナーとか favicon とかが作られるみたいなんだけど、Catalyst::Helper は __DATA__ にヘルパーの中身を書いてて、んでバイナリが混ざってるという。うひょ。

ちなみに開発版は、

svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst Catalyst

で取れます。(via http://www.lost-season.jp/mt/2005/10/200510182.html)

Catalyst::Engine::HTTP::Restarter における自動再起動サーバーの実装

前の話の続き。新しい server.pl は -r オプションをつけたときに、自動的にファイルの修正を検知して再起動してくれる機能が付いてます。

いままでの server.pl だと、デーモン上で perl が永続化してるためにモジュールを書き換えてもそれが再読込されず、一度 ^C で止めてまた起動とかする必要がありました。で、それが必要なくなったと。先日 Rails を試しにいじってたんですが、Rails 付属の WEBrick なサーバーは、クラスの更新も検知してくれてスゲー便利だったので、server.pl がこの仕様になったのはすごくいいです。

どういう実装でこれを実現してるのかなーと思って見てたんですが、やっぱりそこは Catalyst、ちょっと面白い実装になってました。手元にある 5.33 からだと

の二つのクラスが追加されてます。

Watcher は File::Modified を使って、指定したディレクトリの中の .pm ファイルの mtime を監視するクラスで、変更を検知した際にモジュールのシンタックスチェックもしてくれるユーティリティのような役割。特に Catalyst に結合してる感じではないです。

一方の Catalyst::Engine::HTTP::Restarter は Catalyst::Engine::HTTP を継承しています。

  • app_server.pl から Catalyst::Engine::HTTP::Restarter->run が呼ばれる
  • fork する
  • 親は $self->NEXT::runCatalyst::Engine::HTTP->run へ redispatch されデーモンになり HTTP リクエストを待機
  • 子は Watcher インスタンスを作って無限ループの中でモジュールの変更を監視する。
  • 子はモジュールの変更を関知するとソケットで親デーモンの待機ポートに接続し、HTTP で 'RESTART' というメソッドを送信し終了する
  • 親は RESTART メソッドを受け取ると自分自身を実行しているスクリプトを exec して再度自分を実行する

という流れで処理が進んでいきます。ファイルの変更を感知するための処理を NEXT と fork で別プロセスに分離してるのと、子から親へのシグナルに HTTP を使ってるあたりが面白いですね。