# ----------------------------------------------------------------------------- # Tripletail::FileSentinel - ファイルの更新の監視 # ----------------------------------------------------------------------------- package Tripletail::FileSentinel; use strict; use warnings; use Tripletail; use File::Spec; sub _HOOK_PRIORITY() { 1_000_000 } # 順序は問わない our $_INSTANCE; 1; sub _getInstance { my $class = shift; if(!$_INSTANCE) { $_INSTANCE = $class->_new(@_); } $_INSTANCE; } sub __install { my $this = shift; $TL->setHook('postRequest', _HOOK_PRIORITY, sub { $this->__postRequest }); } sub watch { my $this = shift; my $fpath = shift; $fpath = File::Spec->rel2abs($fpath); my $lastmod = (stat($fpath))[9]; if(!$lastmod) { die __PACKAGE__."#watch: failed to stat [$fpath]: $! (ファイルをstatできませんでした)\n"; } if ($TL->INI->get(TL => filelog => 'update') eq 'full') { $TL->log( __PACKAGE__, sprintf( 'Watching file [%s]: last modified time: [%s]', $fpath, scalar(localtime($lastmod)) ) ); } $this->{lastmod}{$fpath} = $lastmod; $this; } sub autoWatch { my $this = shift; my $include = shift; my $exclude = shift; local $_; return unless defined $include || defined $exclude; my @targets = values %INC; @targets = grep m{$include}, @targets if $include; @targets = grep !m{$exclude}, @targets if $exclude; foreach ( @targets ) { $TL->log(__PACKAGE__, " autoWatch(): $_"); $this->watch($_); } $this; } sub _new { my $class = shift; my $this = bless {} => $class; $this->{lastmod} = {}; # {file path => epoch} if(defined($0)) { $this->watch($0); } my $filename = $TL->INI->_filename; if(defined($filename)) { $this->watch($filename); } $this->autoWatch( $TL->INI->get(FileSentinel => 'autowatch_include'), $TL->INI->get(FileSentinel => 'autowatch_exclude') ); $this; } sub __postRequest { my $this = shift; while(my ($fpath, $lastmod) = each %{$this->{lastmod}}) { my $current = (stat($fpath))[9]; if(!$current) { die __PACKAGE__."#postRequest: failed to stat [$fpath]: $! (ファイルをstatできませんでした)\n"; } if($current != $lastmod) { my $time = localtime($current); $TL->log("File Update: file [$fpath] has been updated at [$time]"); $TL->_fcgi_restart(1); } } } __END__ =encoding utf-8 =head1 NAME Tripletail::FileSentinel - ファイルの更新の監視 =head1 SYNOPSIS my $fsenti = $TL->getFileSentinel; $fsenti->watch('/etc/passwd'); $fsenti->watch('/var/log/wtmp'); =head1 DESCRIPTION FCGI モードの際に、特定のファイルが更新されたかどうかを調べて、 更新を検出した場合にプロセスを再起動する。このモジュールは FCGI モードで自動的に使用され、FCGI モードでない時には使用されない。 =head2 METHODS =over 4 =item C<< $TL->getFileSentinel >> my $fsenti = $TL->getFileSentinel; Tripletail::FileSentinel オブジェクトを取得。 =item C<< watch >> $fsenti->watch('/var/log/wtmp'); 監視対象のファイルを追加する。デフォルトでは次のファイルが 監視対象になっている。 =over 4 =item * プロセスの起動に用いられたスクリプト ($0) =item * C<< use Tripletail qw(foo.ini); >> した時の ini ファイル =back =item C<< autoWatch >> $fsenti->autoWatch($include_re, $exclude_re); do, require, use されたファイルを自動的に監視対象に追加する。 具体的には autoWatch の実行時点で %INC に含まれるファイルが監視対象となる。 $include_re, $exclude_re には正規表現を指定する。どちらも指定しなかった場合、 autoWatch は何もしない。 $include_re だけを指定した場合はこれにマッチするパスのファイルが、 $exclude_re だけを指定した場合はこれにマッチしないパスのファイルが、両方を指定した場合は $include_re にマッチして $exclude_re にマッチしないパスのファイルが監視対象となる。 Ini パラメータによる自動監視設定を使用すれば、通常プログラム中で autoWatch を直接呼ぶ必要はないが、 require や do でロードしたファイルを自動監視対象に含めたい場合は require, do の実行後に autoWatch を呼ぶ必要がある。 =back =head2 Ini パラメータ "FileSentinel" グループに autowatch_include または autowatch_exclude を指定すると、 use でロードされたモジュールのうち、条件にマッチするものが自動的に監視対象に追加される。 この機能を使用すれば、スクリプトごとに依存モジュールを watch で指定する必要がなくなる。パフォーマンスを考慮して、 /lib, /usr/lib 等に含まれる、通常は変更しないファイルは autowatch_exclude で監視対象から外すとよい。 =over 4 =item autowatch_include autowatch_include = ^/home/me/my_perl_modules 自動監視対象に含めたいパスを正規表現で指定する。 autowatch_include だけを指定した場合、マッチしたパスのファイルが全て監視対象となる。 =item autowatch_exclude autowatch_exclude = ^/usr/lib/|^/lib/ 自動監視対象から除外したいパスを正規表現で指定する。 autowatch_exclude だけを指定した場合、マッチしないパスのファイルが全て監視対象となる。 autowatch_include と一緒に指定した場合は、 autowatch_include にマッチし、 autowatch_exclude にマッチしないパスのファイルが監視対象となる。 =back =head1 SEE ALSO =over 4 =item L =item L =back =head1 AUTHOR INFORMATION =over 4 Copyright 2006 YMIRLINK Inc. This framework is free software; you can redistribute it and/or modify it under the same terms as Perl itself このフレームワークはフリーソフトウェアです。あなたは Perl と同じライセンスの 元で再配布及び変更を行うことが出来ます。 Address bug reports and comments to: tl@tripletail.jp HP : http://tripletail.jp/ =back =cut