Perl5 での Plack に当たる Crust をみんなで作った話
この記事は Perl 6 Advent Calendar 2015 の1日目です。
Perl 6 は、2015年のクリスマスにリリースされることになっており、我々としてはそれを待ち受ける必要があると考えました。
Perl6 がリリースされた暁には、いろいろ遊ぼうかなという気持ちをみなさんお持ちだと思います。 Perl6 には夢が詰まっており、様々な機能が含まれている夢の言語です。
そういった、夢の機能については今後、クリスマスまでの間に、語られていきますが、本稿では、現実的な話をします。
今年のクリスマスに Perl6 がリリースされるぞ、という宣言がでたわけですが、そうなってくると、Perl6 をクリスマスから早速遊びたいなと思うわけですよね。
そして、私は web engineer なので、 Perl6 が出たら早速 web application を書きたいと思うわけです。
しかし、そこで気づいてしまう。Perl6 には Plack のようなものが無いと!
Perl6 に Plack のようなものがないし、当時まともな httpd の実装が存在していなかったのです! (実際には存在はしていたのですが、multi thread 対応していないし、なぜか当時の MoarVM は listen の backlog が 1 にハードコードされているためにまったく実用的ではなかったのです。この listen のバックログがハードコードされている問題は現在では修正されています)
これではいけない。と気づくわけです。まともな httpd が必要だ。
とりあえず fork(2)
があれば、listen backlog が 1 にハードコードされているというハードな環境下でもなんとかなるだろうと思って、まず NativeCall ( Perl6 から FFI で C 関数をコールする機能) を使って fork を呼ぶようにしてみました。これはなかなかうまく動作したのですが、Mac で動作しないという問題が発見されました。
なぜか。
MoarVM は内部で libuv を利用しており、あらゆるソケット処理に libuv を利用しています。 libuv は fork をサポートしていません。より具体的に言うと mac の kqueue は fork をサポートしてないので、完全に詰みました。
対策として、ソケットライブラリを全部 NativeCall で実装することも考えたのですが(実装もしたのですが)、完全に本質を見失っている感じがしてきたので、この方針は諦めることにしました。
そうこうしているうちに、IO::Socket::Async ベースならわりと動くっぽいのではないかという話になり、IO::Socket::Async ベースで実装する方針に転換しました。
何度か書き直したのですが、まあそこそこ動くようになりました。
そのそこそこ動く実装が HTTP::Server::Tiny です。これは Perl5 の有名な httpd 実装である kazuhooku 氏による Starlet を参考に実装されており、HTTP/1.1 に対応した高速なサーバーです。 (Perl6 でできる範囲としてはかなり高速になるように実装しています。期待したパフォーマンスが出ていなければ、それは、、)
https://github.com/tokuhirom/p6-HTTP-Server-Tiny/
そういうわけで、HTTP::Server::Tiny ができたので、あとは Plack 相当のレイヤーを実装しようということになりました。
そこで、下記12名の Perl Monger が集まり、Plack を Perl6 に移植するプロジェクトに乗り出しました。
- fayland
- hiroraba
- kentaro
- lestrrat
- mattn
- moznion
- retupmoca
- softmoth
- sugyan
- syohex
- syoichikaji
- tokuhirom
https://github.com/tokuhirom/p6-Crust
結果として、2015年12月1日時点でほぼ Plack の機能を実装しております。 例えばイカのように実行すれば、さくっと httpd が立ち上がります。めっちゃ便利。
crustup -e 'sub { 200, [], ["OK"] }'
具体的にはイカのものが完備されています。
- Crust::App::Directory
- Crust::App::File
- Crust::App::URLMap
- Crust::Builder
- Crust::Handler::FastCGI
- Crust::Handler::HTTP::Easy
- Crust::Handler::HTTP::Server::Tiny
- Crust::Headers
- Crust::Middleware::AccessLog
- Crust::Middleware::Auth::Basic
- Crust::Middleware::Conditional
- Crust::Middleware::ContentLength
- Crust::Middleware::ErrorDocument
- Crust::Middleware::Lint
- Crust::Middleware
- Crust::Middleware::ReverseProxy
- Crust::Middleware::Runtime
- Crust::Middleware::StackTrace
- Crust::Middleware::Static
- Crust::Middleware::XFramework
- Crust::MIME
- Crust
- Crust::Request
- Crust::Request::Upload
- Crust::Response
- Crust::Runner
- Crust::Test::MockHTTP
- Crust::Test
- HTTP::Message::PSGI
そんなわけで、ウェブアプリケーションをかく準備は整っています。
あとは Perl6 のリリースを待つだけや!!!!
明日は karupanerura さんの 無限リストであそぶ です。