ホーム

へぼい日記

mod_psgi試してみた

  • 投稿者: chiba
  • 2009/10/16 金曜日 18:17:20
  • perl

mod_psgi をインストールしてみたをみて速くなるなら試してみようということでmod_psgiを試してみますた。

まずはこんな感じの簡単なPSGIアプリで。

my $app = sub {
    return ['200', [Content-Length => '5'], ['hello']];
};
ab -n 10000 -c 100
mod_psgi
 Requests per second:    1403.51 [#/sec] (mean)
mod_perl
 Requests per second:    668.33 [#/sec] (mean)
Standalone
 Requests per second:    702.46 [#/sec] (mean)
Standalone::Prefork
 Requests per second:    725.78 [#/sec] (mean)

おおおお。超絶早いですね!
(plackupの際に-E product(development以外ならなんでもおk)をつけないとだいぶ遅くてそれをそのまま載せてたのを修正しました)

で、お次は、Catalyst::Engine::PSGIを使ってCatalystのhello worldなアプリを。

catalyst.pl Hello

で作って、debugモードを切って、Root.pmのindexで

    $c->response->content_type('text/plain');
    $c->response->body( 'hello' );

こんな感じにしたもの。

ab -n 1000 -c 10
mod_psgi
 Requests per second:    207.87 [#/sec] (mean)
mod_perl
 Requests per second:    144.94 [#/sec] (mean)
cat-standalone
 Requests per second:    184.95 [#/sec] (mean)

おおおおお。早いですね!!これはこれだけでも乗り換える意味がありそうだ。と思ってたんですが現在実運用中のCatalystアプリでやってみたところ”child pid 32320 exit signal Segmentation fault (11)”とかいって死にました。うーむ。これは再現する最小構成を探ってid:spiritlooseさんにフィードバックしたいところですね。

casual-perlerな人たちは今持ってるCatalystアプリをmod_psgi+Catalyst::Engine::PSGIで動かしてどんどんフィードバックするといいんじゃないかな!

はてなブックマーク - mod_psgi試してみた

Archer and Git

  • 投稿者: chiba
  • 3:17:31
  • git

最近会社のレポジトリ管理も順次gitに移行しようとしてるのですが、今までArcher&svnでデプロイしていたものをgit用にarcher.ymlを書き換えしてみた。

汎用的にはこんな感じ。中央サーバのレポジトリにreleaseというブランチを作っておいて、作業者もそれの追跡ローカルブランチなreleaseを作っておくというのが前提。releaseに直接コミットは厳禁。

git stash saveがあるから作業ディレクトリを別に用意する必要ないかなぁとか思ってこんな形にしてみた。今のところ満足してるけど運用しているうちになんか不具合がでるかもしれない。

はてなブックマーク - Archer and Git

Acme::Coro::Sukeをリリースしました

  • 投稿者: chiba
  • 2009/10/12 月曜日 15:44:51
  • perl

多分、5人以上の人が思いついたけどあまりのくだらなさに作成を断念したといううわさのAcme::Coro::Sukeを先ほどCPANにリリースしました。(githubにもあげてあります)

これは、Coroのasyncと基本的には同じ動作をするbenzoというブロック定義ができるようになるもので、benzoブロックにCoroがスレッドを切り替えるたびに、「うわぁ…べんぞうさんの中…すごくあったかいナリぃ… 」とコロちゃんが囁やいてくれるモジュールです。
一番簡単な使い方は以下のようになります。

use Coro;
use Acme::Coro::Suke;
benzo {
};
cede;

enjoy Acme::Coro::Suke!

CPANに上げる三つめのモジュールがAcmeモジュールというのはこれはひどい。

はてなブックマーク - Acme::Coro::Sukeをリリースしました

Re: PSGI Implのsendfileについて

  • 投稿者: chiba
  • 2009/10/7 水曜日 15:29:06
  • perl

PSGI Implのsendfileについてですが、自分の今のところのイメージを書いておくです。

on Plack::Server

  • $res->[2]がGLOBだったら fileno($res->[2])して sendfile に fd を渡す
  • $res->[2]->can(‘fileno’) が生えてたら、$res->[2]->filenoからfdを取って使う
  • $res->[2]->can(‘path’) が生えてたら、$res->[2]->pathからファイルパスを取って使う

$env->{psgix.sendfile}を使わない以外は一緒

on app

realfileをserveしたい時は

  • GLOBを返す
  • ->pathを生やしたIO-Handle-likeなオブジェクトを返す

の二種類の方法があって、後者のほうがあらゆるサーバで最適化される可能性がある。かといって前者だからといってクライアントに届くresponseが変わることはないと期待される。後者において->filenoの実体のファイルと->pathが違うものだった場合の動作は未定義。

on middleware

  • Plack::Middleware::XSendfile
    responseから->pathが取れる場合にはそれをヘッダのX-Sendfileにセットするようなmiddleware。これのpsgix.sendfileサポートを無くしたやつのイメージ。
    X-Sendfileヘッダをセットする場合というのはbackendがlightyの場合とかだと思うけど、それをセットしていいかどうかはPlackは知り得ない。かといってappでセットしていて必要のない時に外にファイルPATHが出ていくものいくない。というわけでappでは->path付きオブジェクトを返すだけにして、このmiddlewareをbackendにあわせて付けたり外したりする。Plack::Server::*のsendfile(2)サポートとかとはまったく関係無い。
  • Plack::Middleware::GuessPath
    GLOBからファイルPathを推測して->path付きのオブジェクトに変換しちゃうMiddleware。マルチプラットフォーム対応が課題。Plack::Middleware::XSendfileより先に実行する。Plack::Server::*のsendfile(2)サポートとも関係する。


追記(10/7 17:24): 大体ここに書いてある感じで追加されたみたいです。詳しくは本家specのchangesetをご覧ください。Plack::Middleware::XSendfileも追加されたみたいです。miyagawaさん仕事ハヤス、、、。

はてなブックマーク - Re: PSGI Implのsendfileについて

ファイルPATHを覚えているfhを作成できるIO::File::WithPathをリリース

  • 投稿者: chiba
  • 1:49:30
  • perl

Plackのsendfileサポート関連を追いかけてて、Plack::Server::Apache2でsendfileサポートされてない理由がfhからファイル名を取るベストな方法がないというわけで、gist: 200797みたいなパッチを書いて#http-engineとかに張り付けたけどそれlinuxでしか動かないよねみたいなことで日本の恥を晒してしまったりしてたわけですが、その中でIO::File::WithPathみたいなのがあればいいよねと話がでていたので作ってみました。

CPANgithubにあげてあります。

使い方はこんな感じ。

    my $fh = IO::File::WithPath->new('/path/to/file');
    print $fh->path; # /path/to/fileがとれるよ
    print $fh->getline; # IO::Handleとしても扱える
    print <$fh>; # もちろんGLOBとしても

Plackのappでは

    return ['200', [], IO::File::WithPath->new('/path/to/file')];

みたいな使い方を想定していますが、Plack::Server側はこのモジュールを使うことが前提というわけではなくて、duck typingで->pathがあるオブジェクトであればそのpathを(使える条件であれば)使うようになる予定だと思います。

あと、純粋なfhからpathを取るマルチプラットフォーム対応なモジュールもできれば欲しいよねというところ。windowsはかなり無理っぽい。

はてなブックマーク - ファイルPATHを覚えているfhを作成できるIO::File::WithPathをリリース

Plack::Requestからのhostのとりかた

  • 投稿者: chiba
  • 2009/9/30 水曜日 21:42:21
  • perl

Plack::Requestにhost無いなぁ。と思って勢い余ってforkしてコミットまでしてしまったのですが、#perl-casual@freenodeで呟いたところyappoさんから

$req->uri->host

もしくはURIオブジェクトの作成コストが気になるなら($req->uriは遅延作成なので)

$req->env->{HTTP_HOST}

でいいじゃんと言われました。確かにその通りですね。

はてなブックマーク - Plack::Requestからのhostのとりかた

Wassrのyapcasia2009チャンネルの発言をIRCに投稿するボットをYAPC::Asiaの二日目向けに作った

  • 投稿者: chiba
  • 2009/9/10 木曜日 23:47:54
  • perl

twitterの#yapcasia2009ハッシュタグがスクリーンに晒されるのが個人的に非常にツボだったので、wassrのyapcasia2009チャンネルに発言するとirc.freenode.orgの#yapc.asia-jaに投稿するボットも作ってみました。
wassrにはstreaming APIはないようなので5秒ごとにpollingしちゃってます。いいんでしょうか。
参考文献(つうかほぼパクリ):
Twitterのハッシュタグ付き発言をIRCに投稿するボットをYAPC::Asia向けに作った

以下コード

#!/usr/bin/perl
use strict;
use warnings;

use AnyEvent::IRC::Client;
use Net::Wassr;
use Encode ();
use Storable;

my $channel = '#yapc.asia-ja';
my $interval = 5;
my $wassr_channel = 'yapcasia2009';

my $wassr = Net::Wassr->new(
    user   => 'nihen',
    passwd => '*****',
);



my $cv = AnyEvent->condvar;
my $pc = AnyEvent::IRC::Client->new;


my $send_message = -e 'send_message' ? retrieve('send_message') : {};
$SIG{INT} = $SIG{TERM} = sub {
    $pc->disconnect('bye');
    store $send_message, 'send_message';
    exit;
};

$pc->reg_cb(
    connect => sub {
        my ( $pc, $err ) = @_;
        if ( defined $err ) {
            warn $err;
            return;
        }
    },
    registered => sub {
        my ( $self ) = @_;
        print "registerd!\n";
        $pc->enable_ping(60);
    },
    disconnect => sub {
        print "disconnected: $_[1]!\n";
    }
);
$pc->send_srv('JOIN', $channel);
$pc->send_chan($channel, 'NOTICE', $channel, 'hi');
$pc->connect('irc.freenode.org', 6667, {
    nick => 'wassr_bot',
    user => 'wassr_bot',
    real => 'wassr_bot',
});

my $w = AnyEvent->timer(after => $interval, interval => $interval, cb => sub {
    my $time_line = $wassr->channel_timeline('name_en=' . $wassr_channel);
    if ( !$time_line || ref $time_line ne 'ARRAY' ) {
        return;
    }

    foreach my $message ( @{$time_line} ) {
        next if $send_message->{$message->{rid}};

        $send_message->{$message->{rid}} = 1;

        $pc->send_chan($channel, 'NOTICE', $channel, Encode::encode('utf-8', $message->{user}->{login_id} . ': ' . $message->{body}));
    }
});


$cv->wait;
はてなブックマーク - Wassrのyapcasia2009チャンネルの発言をIRCに投稿するボットをYAPC::Asiaの二日目向けに作った

YAPC::Asia2009の参加トークをわかりやすくするグリモン作ったよ

  • 投稿者: chiba
  • 2009/9/9 水曜日 14:40:35
  • perl

さて、明日からついにYAPC::Asiaが始まりますね。皆さんは参加されるトークをすでに決められたでしょうか?

参加するトークの詳細ページ(ex.Welcome)でadd to personal scheduleを行うと参加トークの管理ができるようになっているみたいです。ただこれがスケジュール上では確認できなくてちょっと不便だなーと思ったのでわかりやすくするぐりもんを作ってみました。

yapcasia2009myschedule.user.js

です。いれるとスケジュールの表示がこうなります。あ、ログインした状態じゃないと表示されないです。

らくだのマークがわかりやすくて印刷用にも最適ですね!

では、YAPC::Asia会場でお会いしましょうです。

はてなブックマーク - YAPC::Asia2009の参加トークをわかりやすくするグリモン作ったよ

mysqlでskip-character-set-client-handshakeはもう使わないほうがいいと思われ

  • 投稿者: chiba
  • 2009/8/27 木曜日 16:51:43
  • mysql | perl

skip-character-set-client-handshake を [mysqld] セクションに追記すると、クライアントがどんな文字コード設定をもっていようが問答無用で character_set_* を (_system をのぞいて) すべて同じ値に統一してくれる
http://d.hatena.ne.jp/a666666/20090826/1251270979

ふーむ。

skip-character-set-client-handshakeを薦める文書がネット上にはやたら転がってるんだけど、これには大きな落とし穴がある。

たしかに表示されるcharacter_set_*は統一されるかもしれないがこれはあくまでもサーバー側の認識であってクライアント(libmysqlclient)がcharsetをどう認識しているかというのとは関係ないのだ。で、実はlibmysqlclientが認識しているcharsetはcharacter_set_clientとは必ずしも一致しているわけではなくて、これを絶対的に一致させるには以前のエントリでも紹介したがhttp://www.klab.jp/media/mysql/index6.htmlの図3:クライアント側文字コードの指定チャートが参考になる。

skip-character-set-client-handshakeをしただけだと結局libmysqlclientが認識しているcharsetはクライアント側のコンパイル時のcharset(デフォルトではlatin-1)になる。ここで実際に送信するcharsetと乖離が起これば当然組み合わせによってはSQLインジェクションの脆弱性が発生する。id:a666666氏のmysqlはutf8でコンパイルしてujisを送信ということなので脆弱性はなさそうだが(あったら誰か教えてください)、例えばcp932を送信するのであれば以前のエントリと同様に(反対方向だけど)”\xe3\x81\x95\x5c”等が危険な文字列になる。これをlibmysqlclientはUTF-8として認識してエスケープするので”\xe3\x81\x95\x5c\x5c”になるが、サーバー側ではcp932と認識するので”\xe3\x81″ “\x95\x5c” “\x5c”と分割されてしまうという感じだ。

そもそもskip-character-set-client-handshakeなんてのはmysql4.0からの移行組用の臨時救済措置で作られたものだろうし、こんなものを使うことを前提に運用するのはやめたほうがいい。よくいわれている文字コードの変換処理をさせたくない、ということであればフィールドの文字コードと通信の文字コードを統一しておけばいいだけでしょう。

はてなブックマーク - mysqlでskip-character-set-client-handshakeはもう使わないほうがいいと思われ

FormValidator::NestedをCPANにアップしました

  • 投稿者: chiba
  • 2009/8/18 火曜日 21:00:36
  • perl

知人にCPAN Authorになると宣言してから8年、やっとこさなりました。もちろんCPANにアップするだけなら誰だってできるので質の高いモジュールをアップできるように今後は心がけていきたいと思います。

で、初めてアップしたのがFormValidator::Nestedです。

これは、FormValidator::SimpleFormValidator::LiteFormValidator::LazyWayなんかを参考に作られたFormValidatorです。

上記のモジュール達との主な違いといえる特長は、

  • ネストしたパラメータを扱える
  • 配列なパラメータを扱える
  • profileを継承できる

あたりになるかと思います。

profileはとりあえず今はymlで書いて、そのファイルの置かれたbaseディレクトリを指定してそこからの相対PATHがkeyになるという感じです。(FormValidator::Nested::ProfileProviderの実装を増やすことでここは柔軟に対応可能な予定)

params:
  mail:
    name: メールアドレス
    validators:
      - Blank#not_blank
      - Email#email
      - String#max_length:
          max: 100

といった感じのprofileをhoge.ymlとかでprofileディレクトリに保存して

use FormValidator::Nested;
use Class::Param;

my $req = Class::Param->new({mail => 'hoge'});
my $fvt = FormValidator::Nested->new({
    profile_provider => FormValidator::Nested::ProfileProvider::YAML->new({
        dir => 'profile',
    }),
});
my $res = $fvt->validate($req, 'hoge');
if ( $res->has_error ) {
    my $error_param_ref = $res->error_params;
    while ( my ( $key, $error_params ) = %{$error_param_ref} ) {
        foreach my $error_param ( @{$error_params} ) {
            warn $error_param->key . ':' . $error_param->msg;
        }
    }
}

といったコードを実行すると、「mail:メールアドレスの形式が正しくありません」といったwarningが出力されるみたいな使い方ですね。

ネストしたパラメータを扱えるというのはどういうことかというと、

params:
  user:
    name: ユーザ
    nest: hoge

で、huga.ymlを作って(さきほどのhoge.ymlは残したまま)

use FormValidator::Nested;
use Class::Param;

my $req = Class::Param->new({ user => {mail => 'hoge'} });
my $fvt = FormValidator::Nested->new({
    profile_provider => FormValidator::Nested::ProfileProvider::YAML->new({
        dir => 'profile',
    }),
});
my $res = $fvt->validate($req, 'huga');
if ( $res->has_error ) {
    my $error_param_ref = $res->error_params;
    while ( my ( $key, $error_params ) = %{$error_param_ref} ) {
        foreach my $error_param ( @{$error_params} ) {
            warn $error_param->key . ':' . $error_param->msg;
        }
    }
}

とやると「user[mail]:メールアドレスの形式が正しくありません」みたいなwarningになります。ちなみにネストしたパラメータてのはCGI::Expandやそれを利用してるC::P::Params::Nestedなんかの利用を想定してます。Ajaxで動的なフォームを作ったりすると必要になる場面がありますよね。

さらに、配列なパラメータが扱えるというのは

params:
  mail:
    name: メールアドレス
    array: 1
    validators:
      - Blank#not_blank
      - Email#email
      - String#max_length:
          max: 100

とかでbaz.ymlを作っておいて

use FormValidator::Nested;
use Class::Param;

my $req = Class::Param->new({ mail => ['nihen@megabbs.com', 'hoge'] });
my $fvt = FormValidator::Nested->new({
    profile_provider => FormValidator::Nested::ProfileProvider::YAML->new({
        dir => 'profile',
    }),
});
my $res = $fvt->validate($req, 'baz');
if ( $res->has_error ) {
    my $error_param_ref = $res->error_params;
    while ( my ( $key, $error_params ) = %{$error_param_ref} ) {
        foreach my $error_param ( @{$error_params} ) {
            warn $error_param->key . ':' . $error_param->msg;
        }
    }
}

とやるとやはり「mail:メールアドレスの形式が正しくありません」となるという感じです。

あとは、継承ができるという件ですが

extends: hoge
params:
  name:
    name: 名前
    validators:
      - Blank#not_blank
      - String#max_length:
          max: 100

といったprofileを書くとhoge.ymlとHash::Mergeで結合されたprofileが使われるという感じです。Hash::MergeのbehaviorはFormValidator::Nested::ProfileProviderで指定しています。(あー$behaviorはourにしといたほうがいいかな。)

まぁ、こんなところです。ちとPODがぜんぜん書けていないのでこのエントリの内容も含めそのうちPODは書き足しておきます。それまではtディレクトリの中とかをあさってもらうとsampleになるものが一通りそろってるはずです。

あ、それとcodereposにもhttp://svn.coderepos.org/share/lang/perl/FormValidator-Nested/であげてあるのでパッチ等はこちらでいただけるとうれしいです。(まだgithubに移行してない奴)

あーあとfilterも同じymlでかける(ProfileProviderを共有できる)なんて機能もあります。

params:
  tel:
    filters:
      - String#remove_hyphen
      - String#alnum_z2h
    validators:
      - String#between_length:
          min: 10
          max: 11

ま、こんな感じ。

はてなブックマーク - FormValidator::NestedをCPANにアップしました

1 2 3 4 5 6 7 8 9

ホーム

検索
フィード
メタ情報

ページの上部に戻る