Reputation: 63390
I'm having trouble forking a long-running process from some code running under mod_perl2.
Everything works for the most part, but it seems that the forked process is holding open handles to Apache's logfiles - this means Apache won't restart while the process is running (I get a 'failed to open logfiles' message).
Here's the code I'm using:
use POSIX; # required for setsid
# Do not wait for child processes to complete
$SIG{CHLD} = 'IGNORE';
# fork (and make sure we did!)
defined (my $kid = fork) or die "Cannot fork: $!\n";
if ($kid) {
return (1, $kid);
}else {
# chdir to /, stops the process from preventing an unmount
chdir '/' or die "Can't chdir to /: $!";
# dump our STDIN and STDOUT handles
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
# redirect for logging
open STDERR, '>', $log_filename or die "Can't write to log: $!";
# Prevent locking to apache process
setsid or die "Can't start a new session: $!";
# execute the command
exec( $cmd, @args );
die "Failed to exec";
}
Back in the mod_perl1 days, I recall using $r->cleanup_for_exec
to solve this problem, but it doesn't seem to be supported under mod_perl2. (Edit: Apparently it's not required any more..)
Any advice on how to correctly start a long-running process from mod_perl2 without these problems would be greatly appreciated!
Upvotes: 9
Views: 2328
Reputation: 30225
You probably want to read this discussion. It seems you shouldn't fork on mod_perl unless you know how to prepare things. You have to use a module such as Apache2::SubProcess
Upvotes: 3
Reputation: 182782
In my (formerly mod_perl, now FCGI) code, I have in the "else" clause of the "if ($kpid)",
close STDIN;
close STDOUT;
close STDERR;
setsid();
Also, for reasons that I forgot, I immediately fork again, and then in that child re-open STDIN, STDOUT, and STDERR.
So it looks like:
$SIG{CHLD} = 'IGNORE';
# This should flush stdout.
my $ofh = select(STDOUT);$| = 1;select $ofh;
my $kpid = fork;
if ($kpid)
{
# Parent process
waitpid($kpid, 0);
}
else
{
close STDIN;
close STDOUT;
close STDERR;
setsid();
my $gpid = fork;
if (!$gpid)
{
open(STDIN, "</dev/null") ;#or print DEBUG2 "can't redirect stdin\n";
open(STDOUT, ">/dev/null") ;#or print DEBUG2 "can't redirect stdout\n";
open(STDERR, ">/dev/null") ;#or print DEBUG2 "can't redirect stderr\n";
# Child process
exec($pgm, @execargs) ;# or print DEBUG2 "exec failed\n";
}
exit 0;
}
Upvotes: 1