Skip to content

Commit

Permalink
Item6042: make FastCGI engine restart itself automatically if SIGHUP …
Browse files Browse the repository at this point in the history
…recieved or on configuration update

git-svn-id: http://svn.foswiki.org/trunk/FastCGIEngineContrib@1573 0b4bb1d4-4e5a-0410-9cc4-b2b747904278
  • Loading branch information
GilmarSantosJr authored and GilmarSantosJr committed Dec 24, 2008
1 parent 4dca82a commit 942e968
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 16 deletions.
21 changes: 18 additions & 3 deletions FastCGIEngineContrib/bin/foswiki.fcgi
Expand Up @@ -36,9 +36,15 @@ use Getopt::Long;
use Pod::Usage;
use Foswiki;
use Foswiki::UI;
require Cwd;

eval { eval substr($0, 0, 0) };
Foswiki::Engine::FastCGI::reExec() unless $@;
our ($script) = $0 =~ /^(.*)$/;
our ($dir) = Cwd::cwd() =~ /^(.*)$/;

eval { eval substr( $0, 0, 0 ) };
Foswiki::Engine::FastCGI::reExec() unless $@ =~ /^Insecure dependency in eval/;

my @argv = @ARGV;

my ( $listen, $nproc, $pidfile, $manager, $detach, $help );
GetOptions(
Expand All @@ -52,6 +58,9 @@ GetOptions(

pod2usage(1) if $help;

@ARGV = @argv;
undef @argv;

$Foswiki::engine->run(
$listen,
{
Expand All @@ -72,8 +81,14 @@ foswiki_fastcgi [options]
-l --listen Socket to listen on
-n --nproc Number of backends to use, defaults to 1
-p --pidfile File used to write pid to
-M --manager FCGI manager class, defaults to FCGI::ProcManager
-M --manager FCGI manager class
-d --daemon Detach from terminal and keeps running as a daemon
-? --help Display this help and exits
Note:
FCGI manager class defaults to Foswiki::Engine::FastCGI::ProcManager, a
wrapper around FCGI::ProcManager to enable automatic reload of
configurations if changed. If you provide another class, probably you'll
need to restart FastCGI processes manually.
=cut
@@ -1,3 +1,4 @@
bin/foswiki.fcgi 0755
lib/Foswiki/Engine/FastCGI.pm 0644
lib/Foswiki/Engine/FastCGI/ProcManager.pm 0644
data/System/FastCGIEngineContrib.txt 0644
87 changes: 74 additions & 13 deletions FastCGIEngineContrib/lib/Foswiki/Engine/FastCGI.pm
@@ -1,4 +1,4 @@
# Runtime Engine of Foswiki - The Free and Open Source Wiki,
# FastCGI Runtime Engine of Foswiki - The Free and Open Source Wiki,
# http://foswiki.org/
#
# Copyright (C) 2008 Gilmar Santos Jr, jgasjr@gmail.com and Foswiki
Expand All @@ -15,6 +15,20 @@
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
#------------------------------------------------------------------------------
# Parts of this package are based on Net::Server::Daemonize, which is
# Copyright (C) 2001-2007
#
# Jeremy Howard
# j+daemonize@howard.fm
#
# Paul Seamons
# paul@seamons.com
# http://seamons.com/
#
# For more details:
# http://search.cpan.org/perldoc?Net::Server::Daemonize
#------------------------------------------------------------------------------
# As per the GPL, removal of this notice is prohibited.

=begin TML
Expand All @@ -34,6 +48,10 @@ use base 'Foswiki::Engine::CGI';
use strict;

use FCGI;
use POSIX qw(:signal_h);
require File::Spec;

our $hupRecieved = 0;

sub run {
my ( $this, $listen, $args ) = @_;
Expand All @@ -43,14 +61,17 @@ sub run {
$sock = FCGI::OpenSocket( $listen, 100 )
or die "Failed to create FastCGI socket: $!";
}
my %env = ();
else {
sigaction( SIGHUP, POSIX::SigAction->new( sub { $hupRecieved++ } ) )
or warn "Could not install SIGHUP handler: $!";
}
$args ||= {};
my $r = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $sock,
&FCGI::FAIL_ACCEPT_ON_INTR );
my $manager;

if ($listen) {
$args->{manager} ||= 'FCGI::ProcManager';
$args->{manager} ||= 'Foswiki::Engine::FastCGI::ProcManager';
$args->{nproc} ||= 1;

$this->fork() if $args->{detach};
Expand All @@ -59,7 +80,7 @@ sub run {
$manager = $args->{manager}->new(
{
n_processes => $args->{nproc},
pid_fname => $args->{pidfile}
pid_fname => $args->{pidfile},
}
);
$this->daemonize() if $args->{detach};
Expand All @@ -70,6 +91,11 @@ sub run {
}
}

my $localSiteCfg = File::Spec->catpath(
( File::Spec->splitpath( $INC{'Foswiki.pm'} ) )[ 0, 1 ],
'LocalSite.cfg' );
my $lastMTime = (stat $localSiteCfg)[9];

while ( $r->Accept() >= 0 ) {
$manager && $manager->pm_pre_dispatch();
CGI::initialize_globals();
Expand All @@ -79,7 +105,18 @@ sub run {
$this->finalize( $res, $req );
}
$manager && $manager->pm_post_dispatch();
my $mtime = (stat $localSiteCfg)[9];
if ($mtime > $lastMTime || $hupRecieved) {
$r->LastCall();
if ($manager) {
kill SIGHUP, $manager->pm_parameter('MANAGER_PID');
}
else {
$hupRecieved++;
}
}
}
reExec() if $hupRecieved;
FCGI::CloseSocket($sock) if $sock;
}

Expand Down Expand Up @@ -115,15 +152,39 @@ sub reExec {
$ENV{PERL5LIB} .= join $Config::Config{path_sep}, @INC;
$ENV{PATH} = $Foswiki::cfg{SafeEnvPath};
my $perl = $Config::Config{perlpath};
my ($script) = $0 =~ /^(.*)$/;
exec $perl, '-wT', $script, map { /^(.*)$/; $1 } @ARGV;
chdir $main::dir
or die
"Foswiki::Engine::FastCGI::reExec(): Could not restore directory: $!";
exec $perl, '-wT', $main::script, map { /^(.*)$/; $1 } @ARGV
or die "Foswiki::Engine::FastCGI::reExec(): Could not exec(): $!";
}

sub fork {
require POSIX;
fork && exit;
sub fork () {

### block signal for fork
my $sigset = POSIX::SigSet->new(SIGINT);
POSIX::sigprocmask( SIG_BLOCK, $sigset )
or die "Can't block SIGINT for fork: [$!]\n";

### fork off a child
my $pid = fork;
unless ( defined $pid ) {
die "Couldn't fork: [$!]\n";
}

### make SIGINT kill us as it did before
$SIG{INT} = 'DEFAULT';

### put back to normal
POSIX::sigprocmask( SIG_UNBLOCK, $sigset )
or die "Can't unblock SIGINT for fork: [$!]\n";

$pid && exit;

return $pid;
}


=begin TML
---++ StaticMethod detach()
Expand All @@ -135,10 +196,10 @@ Daemonize process. Currently not portable...
sub daemonize {
print "FastCGI daemon started (pid $$)\n";
umask(0);
chdir '/';
open STDIN, "+</dev/null" or die $!;
open STDOUT, ">&STDIN" or die $!;
open STDERR, ">&STDIN" or die $!;
chdir File::Spec->rootdir;
open STDIN, File::Spec->devnull or die $!;
open STDOUT, ">&STDIN" or die $!;
open STDERR, ">&STDIN" or die $!;
POSIX::setsid();
}

Expand Down
51 changes: 51 additions & 0 deletions FastCGIEngineContrib/lib/Foswiki/Engine/FastCGI/ProcManager.pm
@@ -0,0 +1,51 @@
# FastCGI Runtime Engine Component of Foswiki - The Free and Open Source Wiki,
# http://foswiki.org/
#
# Copyright (C) 2008 Gilmar Santos Jr, jgasjr@gmail.com and Foswiki
# contributors. Foswiki contributors are listed in the AUTHORS file in the root
# of Foswiki distribution.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. For
# more details read LICENSE in the root of this distribution.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# As per the GPL, removal of this notice is prohibited.

=begin TML
---+!! UNPUBLISHED package Foswiki::Engine::FastCGI::ProcManager
Wrapper around FastCGI::ProcManager to make FastCGI engine re-execute itself
automatically upon configuration change.
=cut

package Foswiki::Engine::FastCGI::ProcManager;

use base 'FCGI::ProcManager';
use strict;

sub sig_manager {
my $this = shift;
$this->SUPER::sig_manager(@_);
$Foswiki::Engine::FastCGI::hupRecieved++;
$this->n_processes(0);
}

sub pm_die {
my $this = shift;
if ( $Foswiki::Engine::FastCGI::hupRecieved ) {
Foswiki::Engine::FastCGI::reExec();
}
else {
$this->SUPER::pm_die(@_);
}
}

1;

0 comments on commit 942e968

Please sign in to comment.