从Perl在后台运行工作没有等待返回

时间:2010-04-15 15:32:44

标签: php perl unix background

免责声明

首先,我知道这个问题(或密切的变化)已被问过一千次。我真的花了几个小时看着明显的和不那么明显的地方,但可能有一些我想念的东西。

上下文

让我更清楚地定义问题:我正在编写一个新闻通讯应用程序,我希望实际的发送过程是异步的。在用户单击“发送”时,请求立即返回,然后他们可以检查特定页面中的进度(例如,通过AJAX)。它是用传统的LAMP堆栈编写的。

在我正在使用的特定主机中,出于安全原因禁用了PHP的exec()和system(),但Perl的系统函数(exec,system和backticks)却没有。所以我的 workaround 解决方案是在Perl中创建一个“触发器”脚本,通过PHP CLI调用实际的发送者,并重定向到进度页面。

我被困的地方

发件人的电话就行了,截至目前:

system("php -q sender.php &");

问题在于,它不会立即返回,而是等待脚本完成。我希望它在后台运行并让系统调用自己立即返回。我也试过在我的Linux终端上运行一个类似的脚本,实际上直到脚本完成后才会显示提示,即使我的测试输出没有运行,表明它确实在后台运行。

我已经尝试了什么

  • Perl的exec()函数 - 与system()的结果相同。
  • 将命令更改为:“php -q sender.php | at now”),希望“at”守护程序返回,并且PHP进程本身不会附加到Perl。
  • 执行'间接'命令:“/ bin / sh -c'php -q sender.php&'” - 仍然等到sender.php发送完毕。
  • fork()'进程并在子进程中执行系统调用(希望分离进程) - 与上面相同的结果

我的测试环境

为了确保我没有遗漏任何明显的东西,我创建了一个sleepper.php脚本,它在退出之前只睡了五秒钟。还有一个像这样的test.cgi脚本,逐字:

#!/usr/local/bin/perl
system("php sleeper.php &");
print "Content-type: text/html\n\ndone";

我现在该怎么办?

5 个答案:

答案 0 :(得分:9)

基本上你需要'守护'一个进程 - 分叉一个子进程,然后将它与父进程完全断开,这样父进程就可以安全终止而不会影响子进程。

您可以使用CPAN模块Proc::Daemon轻松完成此操作:

use Proc::Daemon;
# do everything you need to do before forking the child...

# make into daemon; closes all open fds
Proc::Daemon::Init();

答案 1 :(得分:7)

有时STDERR和STDOUT也可以锁定系统......为了得到这两者,我使用(对于我使用的大多数shell环境(bash,csh等)):

system("php sender.php > /dev/null 2>&1 &");

答案 2 :(得分:6)

使用fork(),然后在子进程中调用system

my $pid = fork();
if (defined $pid && $pid == 0) {
    # child
    system($command);    # or exec($command)
    exit 0;
}
# parent
# ... continue ...

答案 3 :(得分:1)

另一种选择是设置gearman服务器和进行电子邮件发送的工作进程(或进程)。这样您可以控制同时发送多少电子邮件,并且不需要分叉。客户端(您的程序)可以向齿轮箱服务器添加任务(在后台,无需等待结果,如果需要),并且作业将排队,直到服务器将作业传递给可用工作人员。有齿轮手的perl和php API,所以非常方便。

答案 4 :(得分:0)

管理解决问题。显然,让它无法返回的原因是,以这种方式调用发送方并没有断开stdout。因此,解决方案只是将系统调用更改为:

system("php sender.php > /dev/null &");

感谢大家的帮助。事实上,正是在阅读关于“守护”一个过程的整个故事时,我想到了断开标准输出的想法。