1

我有一个 Perl 插件需要一段时间才能完成操作。该插件通常通过网络从一个 CGI 界面启动,该界面应该在后台发送它并立即打印一条消息。不幸的是,我找不到这样做的方法。我的意思是 CGI 正确启动插件,但它也等待它完成,我不想发生这种情况。我尝试了&forkdetach,甚至Proc::Background,到目前为止还没有运气。我很确定这个问题与 CGI 有关,但我想知道为什么,如果可能的话,解决这个问题。这是我尝试过的代码,请记住,所有方法都可以在控制台中正常工作,只是 CGI 会产生问题。

# CGI
my $cmd = "perl myplugin.pl";

# Proc::Background
my $proc = Proc::Background->new($cmd);
# The old friend &
system("$cmd &");
# The more complicated fork
my $pid = fork;
if ($pid == 0) {
    my $launch = `$cmd`;
    exit;
}
# Detach

print "Content-type: text/html\n\n";
print "Plugin launched!";

我知道 StackOverflow 上有一个类似的问题,但如您所见,它并不能解决我的问题。

4

2 回答 2

4

这基本上是 pilcrow 答案中 shell 在幕后所做的 Perl 实现。它有两个潜在的优势,它不需要使用 shell 来调用你的第二个脚本,并且它在 fork 失败的罕见情况下提供了更好的用户反馈。

my @cmd = qw(perl myplugin.pl);

my $pid = fork;
if ($pid) {
    print "Content-type: text/html\n\n";
    print "Plugin launched!";
}
elsif (defined $pid) {
    # I skip error checking here because the expectation is that there is no one to report the error to.
    open STDIN,  '<', '/dev/null';
    open STDOUT, '>', '/dev/null'; # or point this to a log file
    open STDERR, '>&STDOUT';
    exec(@cmd);
}
else {
    print "Status: 503 Service Unavailable\n";
    print "Content-type: text/html\n\n";
    print "Plugin failed to launch!";
}
于 2012-05-09T15:13:55.527 回答
3

让您的子进程关闭或删除其继承的标准输出和标准错误,以便 Apache 知道它可以自由响应客户端。请参阅 merlyn 关于该主题的文章

例子:

system("$cmd >/dev/null 2>&1 &");

虽然我看到不寒而栗system("$cmd ...")

于 2012-05-09T14:25:41.347 回答