结束 perl 脚本而不等待对 return 的系统调用

End perl script without waiting for system call to return

我是 运行 Linux (Ubuntu 14.04) 上的一个简单的 apache 网络服务器,使用 perl CGI 脚本处理一些请求。该脚本使用 system 函数启动系统命令,但我希望它立即 return,而不管系统调用的结果如何。

我一直在传递给 system 的标量参数末尾添加一个 & 符号(我知道命令注入攻击的含义),尽管这确实会导致系统命令立即 return ,脚本在底层命令完成之前仍不会退出。

如果我使用来自 perl CGI 的 system 调用触发了一个 10 秒休眠的虚拟 ruby 脚本,那么我对 Web 服务器的请求仍然会等待 10 秒才能最终得到响应.我在 system 调用之后放置了一条日志语句,它会在发出 Web 请求时立即出现,因此 system 调用肯定会立即 returning,但脚本仍在等待结束。

This question 类似,但两种解决方案都不适合我。

下面是一些示例代码:

#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use Log::Log4perl qw(:easy);

Log::Log4perl->easy_init(
    { level => $DEBUG, file => ">>/var/log/script.log" } );

print "Content-type: application/json\n\n";
my $cgi = CGI->new();

INFO("Executing command...");
system('sudo -u on-behalf-of-user /tmp/test.rb one two &');
INFO("Command initiated - will return now...");

print '{"error":false}';

编辑:
命令调用是使用 sudo -u 执行的,因为 apache 用户 www-data 需要代表脚本所有者执行脚本的权限,并且我已经为此适当地更新了我的 sudoers 文件。这不是我的问题的原因,因为我也尝试将脚本所有权更改为 www-data 和 运行 system("/tmp/test.rb one two &") 但结果是一样的。

编辑 2:
我还尝试将 exit 0 添加到脚本的末尾,但这没有任何区别。脚本是否有可能立即退出,但 apache 服务器会保留响应直到 perl CGI 调用的脚本完成?或者是否可能是操作系统的某些设置或配置导致了问题?

编辑 3:
运行 直接来自终端的 perl CGI 脚本工作正常。 perl 脚本立即结束,因此这不是 Perl 的固有问题。这大概只能意味着 Apache Web 服务器会保留请求,直到从 system 调用的命令完成。为什么?

Web 服务器创建一个管道来接收响应。它在完成请求之前等待管道到达 EOF。当写入器句柄的所有副本都关闭时,管道到达 EOF。

管道的写入端设置为 child 的 STDOUT。该文件句柄被复制为 shell 的 STDOUT,并再次复制到 mycmd 的 STDOUT。因此,即使 CGI 脚本和 shell 结束并因此关闭了文件句柄的末端,mycmd 仍然保持句柄打开,因此 Web 服务器仍在等待响应完成。

您只需关闭管道写入端的最后一个句柄即可。或者更准确地说,您可以通过将不同的句柄附加到 mycmd STDOUT 来避免首先创建它。

mycmd arg1 arg2 </dev/null >/dev/null 2>&1 &