—# -----------------------------------------------------------------------------
# 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->getFilePath;
if
(
defined
(
$filename
)) {
$this
->watch(
$filename
);
}
$this
->autoWatch(
$TL
->INI->get(
FileSentinel
=>
autowatch_include
=>
undef
),
$TL
->INI->get(
FileSentinel
=>
autowatch_exclude
=>
undef
)
);
$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<Tripletail>
=item L<Tripletail::MemorySentinel>
=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
=back
=cut