Hoppy、中おかわり

Hoppyいいよ:maaash.jp

Hoppyいい

シリコンバレー行った時に参加した Flash Game Summit とかでも、FITC Toronto 2009でも、マルチプレーヤーFlash熱そうだったので自分の周りではきてる。

ということで、Flash XMLSocketサーバ「Hoppy」を奇跡的にも気に入ってくれた方がいらっしゃったみたいで、なんとも嬉しい限りです。

作者としては、いつもの悪い癖で、作りっぱなしの放置プレイ状態だったんですが、せっかく「使ってくれてる感」が漂って来ましたので、今一度、愛情を込めてみようと思います!

というわけで、少し解説記事でも書いておこうかな思うんですが、その前にmashさんの疑問にちょっと回答させていただいときます。

DBとの連携

POEとか使ったシングルプロセスシングルスレッドのデーモンでデータベース扱う時はどうするのがいいんだろう?
裏にDB扱うためだけにhttpサーバ置いてデーモンからはそれに非同期でhttpリクエストするという方法がある。

そうですね。HTTPでjobキューみたいなのを用意するというのもいいですね。

軽めのクエリであればいちいち「あ、いまブロックした〜!」とか気にならないとは思いますが、POEを使ってるとどうしても「ノンブロッキング」にこだわりたくなりますしね。

どうしても気になるようであればPOEでDBIをノンブロッキングで扱ってくれるモジュールを選択するのが良いと思います。POE::Component::EasyDBIとかPOE::Component::SimpleDBIとか。

あとJPAの牧さんが2年くらい前にPOE::Component::MDBAなんてのも書いてます。これは複数のテーブルにどばっとSQL文を同時に投げて、結果をまとめて返してくれるようなモジュールです。複雑なクエリーをPOEから投げなければならない場合には結構おすすめです。以前ちょっと使ってみましたが、mysqlのmergeテーブル使うよりもだいぶパフォーマンスよかった記憶があります。

もしくはjobキューのようなものを準備するのであればQ4Mがおすすめです。POEではないけども、スケールもするし、パフォーマンスも良好です。実際に仕事でQ4M使いまくってますが、いい感じです。

HandlerとServiceの違い

$c->handlerってtcp周りのイベントのハンドラってことでいいのかな。

handlerとserviceについては、ご推察のとおり、tcpレイヤの処理はHandlerとしており、それより上位というかアプリ的に組み込む部分はServiceとしています。

なのでHoppyを使ってアプリケーションサーバを構築する場合は独自にServiceクラスをつくって、それをregistするような感じで使って下さいませ。

github拝見しました

ということでまずはauthを非同期にしてみました。
http://github.com/mash/Hoppy/tree/master

拝見しました。なるほど、そういうことをしたかったんですか。
Hoppy::Room::Memoryをああいう風に拡張するというのは想定してなかったなぁ。

基本的には認証の部分だけ好きなように拡張する事があるだろうと思っていたので、login時に $c->service->{auth} を(登録されていれば)Roomから直接呼び出すようなカタチにしています。ここらへんはちょっと特別扱いなんですが。

でもmashさんのやりたい事はそれでは足りないみたいですね。loginの時だけでなく、logoutでも明示的にhttpを叩きたい、とうようなケースがあるんですね。ここのところはもう少し考えてみます。

設計思想的にはMemoryじゃないもの、例えばmysqlTokyoTyrantなどのストレージでRoomの機能をスケールアウトするような拡張は考慮していたんですが。それこそlogoutは盲点だったです。

あと1点だけ、これは本当はこうして欲しかったな、というポイントがありました。

Auth::Async.pmの中で

c->service->{auth}->login( $args, $poe );

と書かれている箇所がありますが、できればServiceクラスはwork()で統一するような感じがいいかなと。

$self->service->{login}->work( $params, $poe );

一応Service::Baseの中で __PACKAGE__->mk_virtual_methods($_) for qw( work );としておりまして。

純粋仮想関数っぽくインターフェイスを統一、みたいな感じで。。

まぁそこらへんこだわるならいい加減にMooseで書けよ!って話なのかもしれませんが。
なんで、基本的にはお好きなように拡張して使っていただいて構いません。ただのこだわりです。

Yes, It is a BUG!!

$c->regist_service(
auth => 'MyApp::Auth',
);

ってやると $c->handler->{auth} に入るのは気のせいかと思いたかったので
s/handler/service/ してみました。めっちゃコアっぽいけどまぁいいか。

おおお、ご指摘ありがとうございます!
これは全くのミスです。どっしようもないバグです。

って、テストほとんどしてないのがバレバレですね!


githubの方は昼頃に更新しておきました。
CPANはまだ更新してません。あとでサンプルコードとか書いてからあらためてupしようかなと思います。

とりあえずmaaash.jpさんへのお返事エントリでした。