我无法从mod_perl2下运行的某些代码中获取长时间运行的进程。
一切都在大部分工作,但似乎分叉进程持有Apache日志文件的开放句柄 - 这意味着Apache在进程运行时不会重启(我得到'未能打开日志文件'消息)。
这是我正在使用的代码:
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";
}
回到mod_perl1天,我记得使用$r->cleanup_for_exec
来解决这个问题,但mod_perl2似乎不支持它。 (编辑:Apparently不再需要它了。)
如果没有这些问题,如何从mod_perl2正确启动长时间运行的过程的任何建议将不胜感激!
答案 0 :(得分:2)
您可能想阅读this讨论。除非你知道如何准备东西,否则你似乎不应该在mod_perl上分叉。您必须使用Apache2::SubProcess
等模块答案 1 :(得分:1)
尝试在fork之前关闭STDIN / STDOUT句柄。
答案 2 :(得分:0)
在我的(以前的mod_perl,现在的FCGI)代码中,我在“if($ kpid)”的“else”子句中,
close STDIN;
close STDOUT;
close STDERR;
setsid();
另外,由于我忘记的原因,我立即再次分叉,然后在中孩子重新打开STDIN,STDOUT和STDERR。
所以看起来像:
$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;
}