#
# Platon/FastCGI/Restart.pm - check, if FastCGI script or user/system
# modules was modified
#
# Developed by Lubomir Host 'rajo' <rajo AT platon.sk>
# Copyright (c) 2004 Platon SDG, http://platon.sk/
# Licensed under terms of GNU General Public License.
# All rights reserved.
#
# Changelog:
# 09/02/2004 - created
#
# $Platon: web-apps/fastcgi-gallery/_modules/Platon/FastCGI/Restart.pm,v 1.3 2005/09/08 23:34:02 rajo Exp $
package Platon::FastCGI::Restart;
use strict;
use Carp;
use English;
use File::stat;
use Digest::MD5;
use vars qw($VERSION $DEBUG $CLASS @EXPORT $AUTOLOAD);
$VERSION = sprintf("%d.%02d", q$Revision: 1.7 $ =~ /(\d+)\.(\d+)/);
$DEBUG = 0 unless defined $DEBUG;
@EXPORT = qw( add_files add_loaded_modules restart );
sub new
{ # {{{
my ($this, $hash) = @_;
my $self;
if (ref $hash eq 'HASH') {
#warn "Using HASH";
$self = {
restart_func => $hash->{restart_func},
use_lock => defined($hash->{use_lock}) ? $hash->{use_lock} : 'true',
lock_dir => defined($hash->{lock_dir}) ? $hash->{lock_dir} : '/var/tmp',
max_restart_interval => defined($hash->{max_restart_interval}) ? $hash->{max_restart_interval} : 60,
CHECK_USER_MODULES => defined($hash->{CHECK_USER_MODULES}) ? $hash->{CHECK_USER_MODULES} : 'true',
CHECK_SYSTEM_MODULES => defined($hash->{CHECK_SYSTEM_MODULES}) ? $hash->{CHECK_SYSTEM_MODULES} : 'false',
system_modules_regexp => defined($hash->{system_modules_regexp}) ? $hash->{system_modules_regexp}: '^/usr',
};
}
else {
# Defaults:
$self = {
restart_func => &exit(0),
use_lock => 'true',
lock_dir => '/var/tmp',
max_restart_interval => 60,
CHECK_USER_MODULES => 'true',
CHECK_SYSTEM_MODULES => 'false',
system_modules_regexp => '^/usr',
};
}
my $class = ref($this) || $this;
$CLASS = $class;
bless $self, $class;
return $self;
} # }}}
sub add_files ($;@)
{ # {{{
my ($self, @files) = @_;
push @{$self->{checked_files}}, @files;
} # }}}
sub add_loaded_modules ($;)
{ # {{{
my ($self) = shift;
my @keys = sort keys %INC;
#warn scalar(@keys) . " modules loaded";
foreach my $file (@keys) {
if ($INC{$file} =~ m#$self->{system_modules_regexp}#o) {
if ($self->{CHECK_SYSTEM_MODULES} eq 'true') {
#warn "Adding system module '$file'\t=>'$INC{$file}'\n";
push @{$self->{checked_files}}, $INC{$file};
}
}
elsif ($self->{CHECK_USER_MODULES} eq 'true') {
#warn "Adding user module '$file'\t=>'$INC{$file}'\n";
push @{$self->{checked_files}}, $INC{$file};
}
}
} # }}}
sub restart ($;@)
{ # {{{
my ($self, @files) = @_;
my @check_files = @{$self->{checked_files}};
foreach my $file (@files) {
push @check_files, $file if defined $file;
}
my $lock_file;
if ($self->{use_lock} eq 'true') {
$lock_file = "$self->{lock_dir}/fastcgi_restart-$EUID-" . Digest::MD5::md5_hex(join('', @files));
}
if (defined $self->{checked_files}) {
foreach my $file (@check_files) {
my $modif = -M $file;
my $seconds = defined($modif) ? -86400.0 * $modif : 0.0;
if (defined($seconds) and $seconds > 0.0) {
if (defined($lock_file)) { # use lockfiles
if (-f $lock_file) { # lock file exists
my $st = stat($lock_file);
my $lock_modif = time - $st->mtime();
if ($lock_modif < $self->{max_restart_interval}) {
carp "$CLASS: Max. restart interval is $self->{max_restart_interval}, lockfile created $lock_modif seconds ago. Restart delayled ...";
return;
}
}
# create lockfile
open FILE, ">$lock_file" or croak "Can't create lock file '$file': $!";
print FILE $PID; # write pid to this file
close FILE;
}
carp "$CLASS: File '$file' modified $seconds seconds after startup, restarting ...";
&{$self->{restart_func}}; # call function, e.g. exit(0)
}
}
}
else {
croak "$CLASS: Invalid module usage!";
}
} # }}}
sub version ($;)
{ # {{{
return $VERSION;
} # }}}
1;
__END__
=head1 NAME
restart - restart program (e.g. FastCGI script) if modules was moodified
=head1 SYNOPSIS
use lib qw ( path/to/Platon/perl-modules );
use Platon::FastCGI::Restart;
$restart = Platon::FastCGI::Restart->new({
restart_func => sub { $req->LastCall(); exit 0 },
use_lock => 'true',
lock_dir => '/var/tmp',
max_restart_interval => 60,
CHECK_USER_MODULES => 'true',
CHECK_SYSTEM_MODULES => 'false',
});
$restart->add_loaded_modules();
$restart->add_files(@filename_list);
$restart->restart(@other_files);
=head1 EXAMPLE
#!/usr/bin/perl -w
use strict;
use lib qw( ./modules path/to/Platon/perl-modules );
use FCGI;
use Platon::FastCGI::Restart;
use vars qw (
$req $restart
);
$req = FCGI::Request();
$restart = Platon::FastCGI::Restart->new({
restart_func => sub { $req->LastCall() ; exit 0; },
CHECK_USER_MODULES => 'true',
CHECK_SYSTEM_MODULES => 'false',
});
# All modules loaded, push them to the Platon::FastCGI::Restart:
$restart->add_loaded_modules();
my $runlimit = 1000;
my $runcount = 0;
while ( $runcount++ < $runlimit && ($req->Accept() >= 0) ) {
# YOUR CODE HERE
print "Content-type: text/html\r\n\r\n";
$restart->restart($ENV{SCRIPT_FILENAME});
$req->Finish();
}
1;
=head1 DESCRIPTION
The Platon::FastCGI::Restart module cleanly restart your FastCGI script
(or other program), when modules was modified.
=head1 AUTHORS
Lubomir Host 'rajo', <rajo AT platon.sk>
=head1 COPYRIGHT
Copyright (c) 2004 Platon SDG, http://platon.sk/
Licensed under terms of GNU General Public License.
All rights reserved.
=cut
# vim: ts=4
# vim600: fdm=marker fdl=0 fdc=3
Platon Group <platon@platon.sk> http://platon.sk/
|