Re: FastCGI Expert Sought
Matthew Weigel <[email protected]>
| Newsgroups | gmane.comp.web.fastcgi.devel |
|---|---|
| Message-ID | <[email protected]> |
Ross Richey wrote: > So yes this might be something which needs to be handled at the Lighttpd > level. But before we do that I just want to ask the conceptual question: > > Is there some method of nicely killing and respawning a FastCGI process? I run lighttpd on my personal server and do my personal web development as FastCGI; however, I don't rely on lighttpd's process management functionality to do it[1]. If you do use lighttpd's own process management (e.g., specifying in lighttpd.conf the 'bin-path' for a FastCGI process)... first of all, have you looked at http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModFastCGI ? You should be able to set a minimum number of processes, and a maximum number of processes, for that FastCGI server. I *think* - but again, I don't use this part of lighttpd myself - that if you simply configure your Perl program to exit after handling X number of requests, lighttpd will spawn new processes once the number of remaining processes drops below the minimum. PHP has the functionality you're asking about (each child process dies after X requests) built in, without needing to be spawned/managed by lighttpd, and I wrote a small Perl application that does it as well. The traffic I get for this particular web app is minimal, so I've never needed to take the PHP approach of having a master process that manages multiple children who occasionally restart; it's definitely possible though. > The reason I asked for an expert and offered money is that we're fully > expecting that we might have to get someone to actually add that > functionality to FastCGI, but obviously I'm open to other ideas on > fixing the problem. Attached is the skeleton of the Perl application I wrote, minus the actual HTML generation, form handling, etc. It might help with writing a Perl FastCGI server that isn't managed directly by lighttpd. You might have an easier time simply changing your existing code to exit after X requests, but both options are worth considering. It works for me, but that's no guarantee. :-) 1. I do quite a bit to separate privileges and functionality; I have lighttpd configured to chroot itself to /var/www and drop root privileges when it starts, and for example PHP is spawned via lighttpd's spawn-fcgi in a more restrictive chroot (like /var/www/first.example.net/) as a more restricted user. -- Matthew Weigel hacker unique & idempot . ent _______________________________________________ FastCGI-developers mailing list FastCGI-developers-xGejAJT2w6xVgU18Zptdi0EOCMrvLtNR@public.gmane.org http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers
foo_srv.pl
(application/x-perl, 3.3 KB)
#! /usr/bin/perl
# (c) 2009, Matthew Weigel
# All rights reserved.
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
use strict;
use Fcntl qw(:flock);
use English '-no_match_vars';
use FCGI;
use CGI::Fast;
use Proc::Daemon;
use Config::General;
my $config_file = "/etc/foo.cfg";
if ($ARGV[0] eq '-f') {
$config_file = $ARGV[1];
}
my %config
= new Config::General('-ConfigFile' => $config_file,
'-AllowMultiOptions' => 'no',
'-LowerCaseNames' => 1,
'-SplitPolicy' => 'equalsign',
'-CComments' => 0,
)
->getall();
Proc::Daemon::Init();
my $procname = $config{'procname'} || "foo";
my $pidfile = $config{'pidfile'} || "/var/run/$procname.pid";
my $logfile = $config{'logfile'} || "/var/log/$procname.log";
my $socket_path = ":" . $config{'port'};
open(PID, ">$pidfile") or die "Can't open PID file: $!";
my $lock_res = flock(PID, LOCK_EX | LOCK_NB);
die "Can't lock $pidfile: $!" unless $lock_res;
select((select(PID), $OUTPUT_AUTOFLUSH=1)[0]);
print PID "$PID";
open(LOG, ">>$logfile");
select((select(LOG), $OUTPUT_AUTOFLUSH=1)[0]);
log_message("PID is $PID.");
my $socket = FCGI::OpenSocket( $socket_path, 100 );
$CGI::Fast::Ext_Request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR,
\%ENV, $socket, 1);
$SIG{'TERM'} = sub {
log_message("Received SIGTERM, exiting.");
truncate(PID, 0);
flock(PID, LOCK_UN);
close(PID);
close LOG;
$CGI::Fast::Ext_Request->Flush();
$CGI::Fast::Ext_Request->LastCall();
exit();
};
my $counter = 0;
my $reason = "Restarting process to avoid potential memory leaks.";
while (my $cgi = new CGI::Fast) {
log_message("Handling request.");
process_req($cgi);
$CGI::Fast::Ext_Request->Finish();
$counter++;
if ($counter > 1_000) {
last;
}
if (-M $0 < 0) {
$reason = "Script changed, restarting to incorporate changes.";
last;
}
}
log_message($reason);
truncate(PID, 0);
flock(PID, LOCK_UN);
close(PID);
close LOG;
$CGI::Fast::Ext_Request->Flush();
$CGI::Fast::Ext_Request->LastCall();
FCGI::CloseSocket($socket);
exec($0, @ARGV) or print STDERR "couldn't exec foo: $!";
sub process_req
{
# probably do something here
}
sub log_message
{
my ($message) = @_;
print LOG gmtime() . ": $message" . "\n";
}