Sep 16, 2005

MT-XSearchをFastCGI化する

誰もついてきていないみたいな気もするのですが、構わず(いつか誰かの役に立つに違いないと信じて)今度はMT-XSearchをFastCGI化することを考えてみます。

最初にmt-xsearch.cgiをMT::Appに準拠したアプリケーションとして再構成します。実はよく使うMTアプリをとりあえずMT::Appに準拠させておくことは、それ自体意義があります。

と言うのも、MT 3.2では、MT::Appのサブクラスを定義するだけで簡単にMTアプリケーションが構築できるようになっているからです(MTは元来拡張性を考慮して作られていますが、3.2ではそれが一層容易になっています)。このようにして構築されたMTアプリケーションは、mt.cgiの中身を見れば分かるように、ごく簡単なブートストラップスクリプトだけでCGIプログラムとして動作させることができます。それだけではなく、先のエントリーに書いたようにFastCGI化することはもちろん、mod_perl化することも可能です。また、エラーハンドリングやクッキー、セッション管理などいざ一から作ることになったら厄介な作業を代行してくれるsubroutine群も利用できます。つまりは、可用性と保守性の点から望ましいというわけです。

まず、以下のスクリプトをコピペしてextlib/MT/App/XSearch.pmとして保存してください。

package MT::App::XSearch;

use strict;
use MT::App;
@MT::App::XSearch::ISA = qw( MT::App );
use MT::ConfigMgr;
use MT::XSearch;

sub init {
    my $app = shift;
    $app->SUPER::init(@_) or return;
    $app->add_methods(main => \&view);
    $app->{charset} = $app->{cfg}->PublishCharset;
    $app->{default_mode} = 'main';
    $app;
}

sub view {
    my $app = shift;
    my $q = $app->{query};
    require MT::Template;
    require MT::Template::Context;
    my $blog_id = $q->param('blog_id') or
        return $app->error("Missing parameter blog_id");
    my $key = $q->param('search_key') or
        return $app->error("Missing parameter key");
    my $search = MT::XSearch->execute($q);
    my $tmpl = MT::Template->load({ blog_id => $blog_id, 
                                    name => 'XSearch ' . $key,
                                    type => 'custom' });
    my $ctx = MT::Template::Context->new;
    $ctx->stash('MT::XSearch', $search);
    $ctx->stash('CGI', $q);
    my $html = $tmpl->build($ctx)
        or return $app->error("Building search template failed: " . $tmpl->errstr);
    $html;
}

1;

次にオリジナルmt-xsearch.cgiの代わりに以下のブートストラップスクリプトをmt-xsearch.cgiとして保存し、実行パーミッションを設定してみてください。

#!/usr/bin/perl -w

use strict;
use lib 'lib';
use MT::Bootstrap App => 'MT::App::XSearch';

今までのmt-xsearch.cgiと同様に動作するはずです。

これをFastCGI化するのは簡単です。Ogawa::Buzz: MT 3.2 on Apache + FastCGIで述べたdispatch.fcgiに以下のように一行追加し、

my $handlers = {
    'mt.fcgi' => 'MT::App::CMS',
    'mt-comments.fcgi' => 'MT::App::Comments',
    'mt-tb.fcgi' => 'MT::App::Trackback',
    'mt-search.fcgi' => 'MT::App::Search',
    'mt-xsearch.fcgi' => 'MT::App::XSearch',
## uncomment if necessary, but this adds a lot of
## overhead since it loads up LibXML.
##    'mt-atom.fcgi' => 'MT::AtomServer',
};

.htaccessに以下の一行を追加すれば、mt-xsearch.fcgiという名前で、今度はFastCGI化されたMT-XSearchも利用できるようになります。

RewriteRule ^mt-xsearch\.fcgi(.*)$   dispatch.fcgi$1 [L]

ところで上記の方法だと、Ogawa::Buzz: TagwireとMT-XSearchによる動的タグアーカイブなどを実現しようとすると困ったことになります。

ひとつには、

http://www.example.com/blog/tag/MovableType
↓
(snip)/mt/mt-xsearch.fcgi?blog_id=1&search_key=Tagwire&search=MovableType
↓
(snip)/mt/dispatch.fcgi?blog_id=1&search_key=Tagwire&search=MovableType

という二段階のsubstitutionが必要になり、かつURLはrewriteしたくないという要請が発生することです。これはよく検討していませんがApacheのRewriteRuleでは実現できなさそうです。

もうひとつはCGI::Cacheを使ったキャッシングができないということです。

ならば真っ当にmt-xsearch.fcgiを用意してやった方が都合がよいということになります。以下はその例です。

#!/usr/bin/perl -w
use strict;
use lib 'lib';
use MT::Bootstrap;
use CGI::Fast;
use CGI::Cache;
use MT::App::XSearch;

eval {
    CGI::Cache::setup({
        cache_options => { cache_root => './cache', default_expires_in => 600 }
    });
    while (my $q = new CGI::Fast) {
        my $cgi_cache = $q->param('cgi_cache') || 0;
        if ($cgi_cache) {
            CGI::Cache::set_key($q->Vars);
            CGI::Cache::start() or next;
        }
        my $app = MT::App::XSearch->new(CGIObject => $q)
            or die MT::App::XSearch->errstr;
        local $SIG{__WARN__} = sub { $app->trace($_[0]) };
        MT->set_instance($app);
        $app->init_request(CGIObject => $q) unless $app->{init_request};
        $app->run;
        CGI::Cache::stop($app->errstr ? 0 : 1) if $cgi_cache;
    }
};
if ($@) {
    print "Content-Type: text/html\n\n";
    print "Got an error: $@";
}

上記の例ではcgi_cacheというオプションをURLで渡すことによってキャッシュをするかどうかを指定できます。動的タグアーカイブと組み合わせるときには以下のようにRewriteRuleを書けばよいということになります。

RewriteRule ^tag/(.*)$ /mt/mt-xsearch.cgi?blog_id=1&search_key=Tagwire&search=$1&cgi_cache=1 [QSA,L]
2005-09-28追記: mt-xsearch.fcgiに一箇所致命的なミスがありました。17行目に「CGI::Cache::start() or exit;」とか書いてあったのですが、これだとキャッシュにヒットするたびにFastCGIプロセスが終了してしまいます。しかも悪いことにはFastCGIプロセスが終了・再開を頻繁に繰り返すと、mod_fastcgiはbackoff timeを600秒とかに設定してしまい、500 Errorが頻発してしまうわけです。exitではなくnextでしたね。

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

Copyright 2012 Ogawa::Buzz | Powered by Blogger
Design by Web2feel | Blogger Template by NewBloggerThemes.com