Question

I have application that works using Perl's CGI::Fast.

Basically mainloop of the code is:

while (my $cgi = CGI::Fast->new() ) {
  do_whatever( $cgi );
}

Now, I wanted to add ability to kill it, but without disrupting currently processed request. To do so, I added handling to SIGHUP. More or less along the lines:

my $sighupped = 0;
$SIG{ 'HUP' } = sub { $sighupped = 1; };
while (my $cgi = CGI::Fast->new() ) {
  do_whatever( $cgi );
  exit if $sighupped;
}

Which works really great when it comes to "not disturbing process while it handles user request". But, if the process is waiting for new request the sighup-based exit will not be executed until it will finally get some request and process it.

It there any workaround for this? What I would like to achieve it to make the script exit immediately if the HUP (or other signal, it can be changed) reaches it while waiting for request.

Was it helpful?

Solution

You could use the block version of the eval function and the alarm function to add a timeout to Fast::CGI. In the code below I have set a five second timeout. If it times out it will go back to the start of the loop which will check to see if $continue has been set to zero yet. If it hasn't then it we start a new CGI::Fast object. This means that a maximum of five seconds will go by after you send a HUP before the code will start to stop if it was waiting for a new CGI::Fast object (the timeout has no affect on the rest of the loop).

my $continue = 1;
$SIG{HUP} = sub { $continue = 0 };
while ($continue) {
    my $cgi;
    eval {
        local $SIG{ALRM} = sub { die "timeout\n" };
        alarm 5; #set an alarm for five seconds
        $cgi = CGI::Fast->new;
        alarm 0; #turn alarm off
    };
    if ($@) {
        next if $@ eq "timeout\n"; #we will see the HUP signal's change now
        #died for a reason other than a timeout, so raise the error
        die $@;
    }
    last unless defined $cgi; #CGI::Fast has asked us to exit
    do_stuff($cgi);
}

#clean up

OTHER TIPS

You could redeclare your SIGnals based on where the handler is.

If you're outside fast-cgi while loop or inside the fast-cgi polling and thus not in the event loop terminate (basically the default). If you're inside the eventloop logic wait for logic to end and terminate.

Pardon my lack of an editor at the moment.

$inlogic=0;
$hupreq=0;
SIG{SIGHUP}={ exit unless($inlogic); $hupreq=1;}

while()
{
   $inlogic=1;
   function();
   $inlogic=0;
   exit if($hupreq);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top