lighttpd + FastCGI 上で MT3.2 を動作させる方法

Drk7.jp を lighttpd へ完全移行」に書いたとおり、当サイトは lighttpd で運用しているのですが、lighttpd は mod_perl ではなく、FastCGI でスクリプトの高速化をしなくてはなりません。

以前は MovableType を Apache + mod_perl で動作させていましたが、lighttpd では FastCGI で動作させるためにいろいろと小細工が必要でメンドウって事で普通の CGI として動作させていましたが、最近になって管理画面や検索のモッサリ感が耐えきれなくなってきて lighttpd + FastCGI + MT3.2 をやってみました。

- スポンサーリンク -

もともと MT は FastCGI を前提とした作りにはなっていないので、ディスパッテャーを作成してやる必要があります。mod_perl + MT に比べて極端に情報が少ないのですが、ネットで調べると次のサイトが有益な情報を発信しています。
ちなみに、この情報は MT3.2 向けの情報になります。その他の環境では若干異なると思いますのでご了承下さい。

Apache + FastCGI の情報でも lighttpd + FastCGI の参考にはなります。

(1) lighttpd + FastCGI + MT3.2 のキモでもある MTdispatch.fcgi を作成します。

このスクリプトは、mt.cgi や mt-search.cgi と同じディレクトリ配下に作成して下さい。赤く表示された部分は、ご自分の環境に合わせて変更下さい。
#!/usr/bin/perl -w
use strict;
use lib '/path_to_mt/lib';
use lib '/path_to_mt/extlib';

use MT::Bootstrap;
use CGI::Fast;
use Data::Dumper; my $handlers = {
'mt.cgi' => 'MT::App::CMS',
'mt-comm.cgi' => 'MT::App::Comments',
'mt-tb.cgi' => 'MT::App::Trackback',
'mt-search.cgi' => 'MT::App::Search',
# 'mt-atom.fcgi' => 'MT::AtomServer',
};
eval "use $_" foreach (values %$handlers); eval {
while (my $q = new CGI::Fast) {
my $cgi = $q->url;
$cgi =~ s!.*/!!;
my $pkg = $handlers->{$cgi};
die "Invalid handler for $cgi" unless $pkg;
my $app = $pkg->new(CGIObject => $q) or die $pkg->errstr;
local $SIG{__WARN__} = sub { $app->trace($_[0]) };
MT->set_instance($app);
$app->init_request(CGIObject => $q) unless $app->{init_request};
$app->run;
my $mode = $app->mode || '';
if ("$pkg->$mode" eq 'MT::App::CMS->plugin_control') {
exit; # allows server to recycle after changing plugin switches
}
}
};
if ($@) {
print "Content-Type: text/html\n\n";
print "Got an error: $@";
}

このスクリプトは他のサイトで更改されているものとほぼ同じですが、ちょっと踏み込んで解析してみました。動作のロジックは、
FastCGI インスタンスを生成
 ↓
url を解析して、該当するApp インスタンスを生成。
※引数として FastCGIObject を渡すと、lib/MT/App.pm 内の init_request メソッドで新規に CGI オブジェクトを生成しない。
 ↓
Apache + mod_perl Handler で動作させるときに実行される lib/MT/App.pm 内の sub handler ($$) メソッドと同様の初期化処理。
 ↓
$app->run;

となります。

(2) lighttpd.conf を設定して dispatcher とスクリプトの連携を設定します。

赤く表示された部分は、ご自分の環境に合わせて変更下さい。
fastcgi.server = (
"/MTdispatch.fcgi" => (
"MTdispatch" => (
"socket" => "/tmp/fastcgi_mtdispatch.socket",
"bin-path" => "/path_to_mt/MTdispatch.fcgi",
"min-procs" => 1,
"max-procs" => 1,
"idle-timeout" => 20,
"bin-environment" => (
"MT_HOME" => "/path_to_mt",
"MT_CONFIG" => "/path_to_mt/mt-config.cgi"

)
)
), url.rewrite = (
"^(.*)/mt\.cgi(.*)$" => "$1/MT/MTdispatch.fcgi$2",
"^(.*)/mt-comments\.cgi(.*)$" => "$1/MT/MTdispatch.fcgi$2",
"^(.*)/mt-tb\.cgi(.*)$" => "$1/MT/MTdispatch.fcgi$2",
"^(.*)/mt-search\.cgi(.*)$" => "$1/MT/MTdispatch.fcgi$2",
)

取りあえず、以上で既存の MT スクリプトには何も変更を加えることなく lighttpd + FastCGI + MT3.2 が動作しますが、実は mt-search.cgi 等で検索結果が2回目以降が正常に表示されない不具合があります。

(3) とりあえず MT 3.2日本語版Unofficial Patch をあてる

まずは MT3.2 の typo 等を修正する mt32-uo-patch.diff をあてます。patch の当て方が分からない場合は、直接エディタで編集しても良いと思います。 これだけでも不具合は解消されません。更に patch をあてます。
Index: lib/MT/App.pm
===================================================================
--- lib/MT/App.pm (revision 8)
+++ lib/MT/App.pm (revision 12)
@@ -164,7 +164,7 @@
my @req_vars = qw(mode __path_info _blog redirect login_again
no_print_body response_code response_content_type response_message
author cgi_headers breadcrumbs goback cache_templates warning_trace
- cookies _errstr request_method);
+ cookies _errstr request_method results);
delete $app->{$_} foreach @req_vars;
$app->{trace} = '';
$app->{author} = $app->{$COOKIE_NAME} = undef;
Index: lib/MT/App/Search.pm
===================================================================
--- lib/MT/App/Search.pm (revision 8)
+++ lib/MT/App/Search.pm (revision 12)
@@ -127,6 +127,7 @@
sub execute {
my $app = shift;
my @results;
+ $app->{search_string}= $app->{query}->param('search') || '';
if ($app->{searchparam}{Type} eq 'newcomments') {
$app->_new_comments
or return $app->error($app->translate(

MT3.2 を mod_perl や FastCGI 上で動作させると lib/MT.pm の init メソッド内の $mt->read_config(\%param) or return; において mt-config.cgi を一度メモリ上にキャッシュしたら二度目からは return; して高速化を図っています。
ここが不具合の発生原因のキモでして、その他のモジュールの init メソッド内の

sub init {
my $app = shift;
$app->SUPER::init(@_) or return; ・・・以下、個別の初期化処理・・・

においても、2度目以降は $app->SUPER::init(@_) or return; で return して1度しか評価されない仕組みになっています。つまり、init メソッド内に CGI-query の受け渡しを記述した場合や変数の初期化処理をしても無意味ということになります。

したがって、リクエスト毎に変数の初期化や query の値を評価する場合は、execute メソッド内に記述してやる必要があるわけです。今回は mt-search.cgi しか重点的に見ていませんが、その他のスクリプトでも同様の不具合が発生していて困っている場合は、(3)と同様に execute メソッドに変数の初期化処理や query 評価を持ってくれば良いと思います。

- スポンサーリンク -