#10 2012年に作ったものを振り返りつつProcletマジ便利

2012年も残すところあと20日ほどとなりましたが皆様いかがお過ごしでしょうか。@fujiwara です。

このエントリは tech.kayac.com Advent Calendar 2012 10日目の記事です。

テーマが「私の中のマイイノベーション 2012」ということで、まずこの1年に作ったものを自分の blog エントリから振り返ってみますと…

こう振り返ってみると fluentd 関連が非常に多くて、やはり自分の中でもホットなプロダクトだったのだなと思います……が、ここから先は fluentd は関係なく、kazeburo さんが書かれた Proclet が便利だよーというお話をしたいと思います。


最近、『jobの一時保管 & 再実行機能付き job queue』という不思議なものを Perl で書きました。 Surface - github

メインで利用している Zabbix の監視に対して、外部の別のネットワークから Zabbix Server やそれが配置されているネットワークが落ちていないかを監視するための、サブシステムを作るために用意したものです。

  • 監視項目の定義はメインの Zabbix で一元化したい
  • メインのホストが落ちている間も、定期的に外部監視を実行したい

という要件があったため、Zabbix上で定義したアイテムを zabbix-agent 経由で job queue に投入し、job workerが監視を実行。jobの投入が一定時間以上途絶えた場合には、最近投入されたjobを定期的に再実行することで、監視を継続するような仕組みです。

job queue の実装には Redis を用いて、以下のような処理を行っています。

  • RPUSH で job を LIST に投入
  • BLPOP で worker が job を取得して処理
  • Sorted Set で最近投入された job を保管

また、job の投入を curl などで簡単に行うために、Plack を利用した HTTP API も用意しました。

つまり、これらが動作するためには以下の4つのプロセスが同時に動作する必要があります。

  1. job の再実行を管理する manager
  2. job を処理して監視を行う worker
  3. job 投入 HTTP API のための PSGI application
  4. queue を実装するための Redis

これをいちいち、daemontools やら supervisor などでプロセスを起動するのは面倒ですよね。本番ならまだしも、開発中ならなおさらです。

……ということで、前置きが大変長くなりましたが、Proclet を利用することで、これらの複数プロセスを一つのスクリプトで管理することができて、ものすごく便利なのです!

例: https://github.com/fujiwara/Surface/blob/master/examples/surface_service

Proclet::Declareを使用することで、redisを子プロセスとして起動するのは1行です。

use Proclet::Declare;
service("redis", "redis-server", "redis.conf");

Manager や API プロセスは Perl で動作するので、コードで記述できます。

service(
    "api",
    sub {
        Surface::WebAPI->new(...)->run( "-p" => "9000" );
    }
);

worker に同じプロセスを3つ起動したい場合も簡単。

service(
    "worker",
    sub {
        while (my $msg = $surface->dequeue) {
            next unless $msg;
            infof "worker[%d]: got message %s", $$, ddf $msg;
        }
    }
);
worker(
    worker => 3,
);

各プロセスが標準出力、標準エラー出力に吐き出す内容を、色分けして表示できます。

color;
run;

proclet.png

いやあ、Proclet マジ便利ですね!!

開発中に Redis, memcached などのアプリケーションから利用するミドルウェアを起動したり、外部の Web API を呼び出すアプリケーションを開発するために、ダミーの実装を立ち上げておきたい、などの目的にも使えます。

Plack::Runner を使うと、app.psgi をファイルとして用意しなくても plackup 同様のオプションで起動できて、管理が楽になりますね。

service('dummy_api', sub {
    my $app = sub {
        [ 200, ["Content-Type", "text/plain"], ['{"success":1}'] ];
    };
    my $runner = Plack::Runner->new;
    $runner->parse_options("-p", 5001);
    $runner->run($app);
});

ということで、大変便利な Proclet、おすすめですので是非使ってみてください。

明日は @9renpoto さんのエントリーですのでお楽しみに!