在Perl的后台运行工作,无需等待退货

免责声明

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

上下文

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

在我使用的特定主机中,出于安全原因,PHP的exec()和system()被禁用,但是Perl的系统函数(exec,system和backticks)却没有。 所以我的 解决方法 解决scheme是在Perl中创build一个“触发器”脚本,通过PHP CLI调用实际的发件人,并redirect到进度页面。

我困在哪里

到目前为止,发件人的电话号码是:

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

问题是,它不是立即返回,而是等待脚本完成。 我希望它在后台运行,并让系统调用自己立即返回。 我也尝试在我的Linuxterminal上运行一个类似的脚本,事实上这个提示不会显示,直到脚本完成后,即使我的testing输出没有运行,表明它真的在后台运行。

我已经试过了

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

我的testing环境

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

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

我现在该怎么办?

基本上,你需要“守护进程”一个进程 – 分离一个孩子,然后完全断开它与父母,使父母可以安全地终止而不影响孩子。

您可以使用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(); 

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

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

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

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

另一个选择是建立一个传动员服务器和一个工作进程(或多个进程)来完成电子邮件。 这样,您就可以控制同时发送多少电子邮件,而且不需要任何分派。 客户端(你的程序)可以添加一个任务给gearman服务器(如果需要的话,不需要等待任何结果),这个任务就会排队,直到服务器把这个任务交给一个可用的worker。 有perl和PHP的API的齿轮,所以这是非常方便的。

管理解决问题。 很明显,阻止它返回的原因是以这种方式调用发送方不会中断标准输出。 所以,解决方案只是简单地将系统调用更改为:

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

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