morboとhypnotoadの違いとハマりどころ


最近はMojoliciousも少しずつ使っています。@[xtetsuji](https://twitter.com/xtetsuji) です

今回は、以前どこかの勉強会で質問に挙がったことを思い出して書いてみます。

## Mojoliciousのビルトインサーバ2つ

先日の@[yusukebe](https://twitter.com/yusukebe)さんのアドベントカレンダーでは、`plackup`を使ってPSGIアプリとして起動する方法が解説されていましたが、Mojoliciousには最初から以下の2つのウェブサーバが同梱されています。

- morbo (モーボと読むらしい)
- hypnotoad (ハイプノトードと読むらしい)

この他にも、[Mojolicious](http://search.cpan.org/dist/Mojolicious/)のMojo::Server::* 名前空間を見てみると、PSGIやらCGIやら、他の起動方法についてのサポートもあります。`mojo help` コマンドの出力も簡潔で参考になるでしょう。

## morboとhypnotoadのプロセス起動方法の違い

`mojo generate app` もしくは `mojo generate lite-app` から作った場合、`script/` ディレクトリ以下に起動スクリプトが出来ているはずです。

```perl
#!/usr/bin/env perl

use strict;
use warnings;

use FindBin;
BEGIN { unshift @INC, "$FindBin::Bin/../lib" }

# Start command line interface for application
require Mojolicious::Commands;
Mojolicious::Commands->start_app('YourApp::Web');
```

@yusukebe さん的に、コントローラーのために **Web** という名前空間のクッションを置いています。こういうふうにすることで、`YourApp::*` 直下の名前空間に、直接Mojolicious(ウェブ関連)とは関係なのないCLIツールであったりDB関連モジュールを置くことができます。

このスクリプトが `script/your_app` であるとして、開発時に morbo を使って起動すると以下のような出力がなされます。

```bash
$ morbo script/your_app 
Server available at http://127.0.0.1:3000.
```

morboの詳細は`morbo help`などを参照してください。いたってシンプルです。

morbo は開発サーバなので、特に大規模アクセスを受ける必要のない単一のプロセスとなっています。

`pstree`コマンドで見てみると以下のようになっています。 (`pstree`コマンドの実装によっても出力は多少変化します)

```bash
 | |-+= 00134 ogata /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -psn_0_40970
 | | |-+= 00213 root login -pf ogata
 | | | \-+= 00217 ogata -bash
 | | |   \-+= 33824 ogata perl /Users/ogata/perl5/perlbrew/perls/perl-5.18/bin/morbo script/your_app
 | | |     \--- 33825 ogata /Users/ogata/perl5/perlbrew/perls/perl-5.18/bin/morbo  
```

起動したターミナルから1プロセスがぶら下がっているだけですね。

morboが便利なのは、起動しっぱなしでも起動後に更新されたモジュールがロードされるところなどでしょう(`plackup` の `-r` や `-R` オプションと同様)。

ただ、hypnotoad は標準で4プロセスを同時起動します。

```bash
$ hypnotoad -f script/try_app 
Server available at http://127.0.0.1:8080.
```

`-f` オプションを指定しないとバックグラウンドに回って、起動したターミナルのジョブではなくなってしまうので、とりあえずこの例では`-f`オプションをつけています。

```bash
 | | | \-+= 00217 ogata -bash
 | | |   \-+= 33931 ogata /Users/ogata/your_app_script/your_app 
 | | |     |--- 33932 ogata /Users/ogata/your_app_script/your_app 
 | | |     |--- 33933 ogata /Users/ogata/your_app_script/your_app 
 | | |     |--- 33934 ogata /Users/ogata/your_app_script/your_app 
 | | |     \--- 33935 ogata /Users/ogata/your_app_script/your_app 
```

親プロセス1つに、子プロセス4つがぶら下がっている形になっています。Apacheなどでお馴染みのpreforkモデルですね。実際にHTTPの処理を行うのは子プロセスになります。

ただ、開発時に morbo の場合は1プロセスだったのが、商用環境時のhypnotoad ではpreforkの複数プロセスになることで、ハマるポイントが出てくるかもしれません。

秘匿なデータを入れられませんが、MojoliciousではCookieを少しだけ使いやすくした `$self->session()` が取り急ぎ使えるのと、大きなデータや秘匿なデータであればサーバ側にセッションストレージを持つはずなので、グローバル変数で抱えていたものがmorboからhypnotoadになってから意図しないことになったということはあまりないかと思いますが、複数人で開発しているとハマる可能性も出てくるかもしれません。アクセス数に応じてカウントアップをしているstate変数のようなものが便宜的に用いられてコード中に潜んでいるケースがあったりして、morboの場合は重複がなかったのに、hypnotoadでは1がたくさん出る、といった症状に見舞われることもあるかもしれません。

また、モデル側で同時接続数が限られているものについても注意が必要です。

Mojoliciousでは[イベントループ](http://mojolicio.us/perldoc/Mojolicious/Guides/Cookbook#Event_loops)の扱いも様々で、AnyEventを使ったりもできます。AnyEventは豊富なライブラリがたくさんあって多種多様なことができますが、同時並行的にモデル側(TwitterのAPIであるとか)にアクセスすると、morboの場合は顕著化しなかった複数の同時アクセスが生まれてしまうこともあり、同時アクセスに厳しいAPIがhypnotoadにすると挙動がおかしく見えるという場合もあります。

## Mojoliciousではmorboとhypnotoadを使ったほうがよい？

@yusukebeさんの記事だと `*.psgi` を作って `plackup` するという方法が解説されています。Mojoliciousは本当に色々なものが揃っているものの、サイトが巨大になってくると、Mojoliciousではやりづらいことが出てきても、Plackのエコシステム(Middlewareなど)でできたりするのは魅力的です。

Plack自体のインストールも`cpanm`コマンドで簡単にできる時代ですが、諸々の理由で環境に制約がある場合(受託納品型開発で依存モジュールが増えると苦労が増える場合など)には、Mojoliciousパッケージ単体で完結することは魅力的ではあります。

`hypnotoad --help` をすると、簡素なことしかできないような印象を覚えますが、その場合は `Mojo::Server::Hypnotoad` を直接呼び出すスクリプトを書くなどしてパラメータの調整などが可能です。詳しくは `perldoc Mojo::Server::Hypnotoad` を参照ください。

----

もうちょっと基本的な「Mojoliciousことはじめ」的な記事もほしいですね。余裕があればそう言うのも書いてみようと思います。