Perlを中心とした技術系の話などをつらつら

2004年12月26日

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}) {

Technorati TAGTechnorati TAG , ,

Posted by horiuchi at 2004年12月26日 20:21

Continuing the discussion...

このエントリーのトラックバックURL:
http://hori-uchi.com/mt/trackback/248

Comments

Post a comment




Remember personal info?