2004年12月27日月曜日

Class::DBIとApache::ReloadでInternal Server Error

mod_perlで動作するアプリケーションを開発する場合、更新されたモジュールをリロードしてくれるApache::Reloadのようなモジュールを利用するのが一般的だと思いますが、Apache::Reloadが有効になっている状態でClass::DBIを継承したモジュールを更新すると以下のようなエラーメッセージをはいてInternal Server Errorになるという現象に悩んでました。

>

[Sun Dec 26 20:06:02 2004] [error] Can't use an undefined value as a HASH reference
at /usr/local/perl-5.8.5/lib/site_perl/5.8.5/Class/DBI/Relationship/HasMany.pm line 51.\n
Compilation failed in require at /usr/local/perl-5.8.5/lib/site_perl/5.8.5/Apache/Reload.pm line 140.\n

<

そこで少し調べてみると、Re: Apache::Reload and CDBI won't play togetherに次のような記述が。

>
Class::DBI prevents you from overwriting already declared methods. To
fix this, you would need to hack Apache::Reload to clear the symbol
table of your package just before reloading it, or hack Class::DBI to
ignore overwriting subs.
<

Class::DBIはすでに宣言されているメソッドの上書きをさせないのが原因で、これを回避するには、リロードされる前にシンボルテーブルをクリアするようにApache::Reloadをhackするか、上書きを無視するようにClass::DBIをhackしろということのようです。

そこで今回は開発環境でしか使わないApache::Reloadをhackし、パッチを書いてみました。(Class::DBIに比べてApache::Reloadはコードの量が少ないのでhackが簡単。)

>

--- Reload.pm.orig 2004-12-26 19:35:31.000000000 +0900
+++ Reload.pm 2004-12-26 20:22:40.000000000 +0900
@@ -122,6 +122,14 @@
}

if ($mtime > $Stat{$file}) {
+ my $package = $key;
+ $package =~ s/\//::/g;
+ $package =~ s/\.pm$//;
+ if ( UNIVERSAL::isa($package, 'Class::DBI') ){
+ no strict 'refs';
+ warn "Apache::Reload: clear the symbol table of $package\n" if $DEBUG;
+ %{"$package\::"} = ();
+ }
delete $INC{$key};
# warn "Reloading $key\n";
if (my $symref = $UndefFields{$key}) {
<



0 件のコメント:

コメントを投稿