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

Raf*_*ida 9 php unix perl background

免责声明

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

上下文

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

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

我被困在哪里

截至目前,发件人的电话就是这一行:

system("php -q sender.php &");
Run Code Online (Sandbox Code Playgroud)

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

我已经尝试过了什么

  • Perl的exec()函数 - 与system()相同的结果.
  • 将命令更改为:"php -q sender.php | at now"),希望"at"守护程序返回,并且PHP进程本身不会附加到Perl.
  • 执行命令'indirect':"/ 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";
Run Code Online (Sandbox Code Playgroud)

我现在该怎么办?

Eth*_*her 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();
Run Code Online (Sandbox Code Playgroud)


小智 7

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

system("php sender.php > /dev/null 2>&1 &");
Run Code Online (Sandbox Code Playgroud)


mob*_*mob 6

使用fork()然后调用system子进程.

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