PSGI/Plack/PSGIアプリケーションを動かす時に一番使われているのは plackup でしょう。

$ cat app.psgi
use Plack::Builder;
use MyApp;
my $app = MyApp->psgi_app;
builder {
    enable 'ServerStatus::Lite', => ..;
    $app;
};
$ plackup -E production -s Starlet --max-workers 30 --port 5000 -a app.psgi

plackup コマンドの -s にハンドラ名を指定して起動します。本番環境では -E や $ENV{PLACK_ENV} を指定してStackTraceやLintといった開発に便利なPlack::Middlewareが追加されないようにする必要がありますね。

Starmanの場合は、starman コマンドも用意されていて

$ starman  --workers 30 --port 5000 --preload-app --disable-keepalive app.psgi

のようにしていると思います。starmanコマンドの場合はデフォルトで-E(env)が deployment となります。

plackupやstarmanコマンドが利用しているのが Plack::Runner です。

my $runner = Plack::Runner->new();
$runner->parse_options(qw/-E production -s Starlet --max-workers 30 --port 5000 -a app.psgi/);
$runner->run();

Plack::Runnerが plackup コマンドの実装そのもので、渡されたオプションの解析と、PSGIアプリケーションの読み込み方法(RestarterやShotgunなどのPlack::Loader)の設定などを行っています。

Plack::LoaderはPlack::Runnerから呼び出されますが、別のモジュール内やスクリプトからPlackのサーバを起動したい場合などに直接使う事もできます。Plack::Loaderにはpsgiファイルの読み込み機能がないので、自前で用意する必要があります。また、PLACK_ENVを自動で設定することもありません。

my $app = MyApp->psgi_app;
$app = builder {
    enable 'ServerStatus::Lite', => ..;
    $app;
};

my $handler = Plack::Loader->load(
    'Starlet',
    max_worker => 30
    port => 5000
);
$handler->run($app);

と、ここまでくると、直接 Plack::Handler を使う事もでき、

my $handler = Plack::Handler::Starlet->new(
    max_worker => 30
    port => 5000
);
$handler->run($app);

とも書けます。

本番環境でのあれこれ

本番環境でも plackup が使われていることが多いのですが、2つほど困る事があります。1つ目はPLACK_ENVの指定し忘れで開発用のStackTraceなどが読み込まれてしまう事故。もうひとつがServer::Starterと組み合わせたときに起動オプションの変更が kill -HUP では出来ないことです

無停止でのアプリケーションの再起動を行うためにServer::Starter(start_server)を使っている思いますが、例えば、daemontoolsのrunファイルに

export PATH=...
exec start_server --port 5000 --signal-on-hup=USR1 \
      -- plackup -E production -s Starlet --spawn-interval=1 --max-worker=5 -a /path/to/app.psgi 2>&1

と書いて実行していて、「いっけねー、ワーカー少なすぎたわー」となった時に、runファイルを書き換えて、svc -h してもワーカーの数は変わってくれません。svc -t などで一度Server::Starterごと停止して、新しいオプションでServer::Starterを起動しなおす必要があります。これではせっかく無停止でのアプリケーションの再起動ができるのに残念です。

そこでおすすめなのが、plackup をシェルスクリプトなどでラップする方法と、plackup を使わない方法です

シェルスクリプトの場合、

$ cat app.sh
DIR=$(cd $(dirname $0) && pwd)
exec plackup -E production -s Starlet --spawn-interval=1 --max-worker=5 -a $DIR/app.psgi

$ cat /service/myapp/run
...
exec start_server --port 5000 --signal-on-hup=USR1 -- /path/to/app.sh 2>&1

となります。この方法だと app.sh を書き換えて svc -h すると app.shが必ず再実行されるのでオプションの変更も適用されるはずです。この方法はmala氏に教えてもらいました。

もうひとつが plackup を使わない方法。上で紹介したPlack::Runnerなどのモジュールを使い、本番環境用起動コマンドを書くというもの。できるだけPLACK_ENVの指定し忘れ事故を防ぐ構成になっていると良いんじゃないかなぁと思います。

例えば、Plack::Loaderを使うようにすると、PLACK_ENVの有る無しによって動作が変わってしまうことはなくなります

$ cat produnction_server.pl
#!/usr/bin/env perl

use strict;
use warnings;
use FindBin;
use Plack::Util;
use Plack::Loader;
use Plack::Builder;

my $app = Plack::Util::load_psgi $FindBin:Bin . '/app.psgi';
$app = builder {
    enable "ServerStatus::Lite", ...;
    $app;
};
Plack::Loader->load(
    'Starlet'
    'max_workers' => 30,
    'port' => 5000
)->run($app);

どうでしょうか?

このブログ記事について

このページは、Masahiro Naganoが2013年6月 7日 16:06に書いたブログ記事です。

ひとつ前のブログ記事は「Test::TCP でサーバが起動するまで待つ時間を変更する」です。

次のブログ記事は「Released AnyEvent::DNS::Cache::Simple. DNS cache extension for AnyEvent」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

OpenID対応しています OpenIDについて
Powered by Movable Type 4.27-ja