# # Platon/FastCGI/Restart.pm - check, if FastCGI script or user/system # modules was modified # # Developed by Lubomir Host 'rajo' # 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', =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