从 Perl 在后台运行作业而不等待返回
首先,我知道这个问题(或相近的变体)已经被问过一千次了.我确实花了几个小时寻找明显和不那么明显的地方,但我可能遗漏了一些小东西.
First of all, I know this question (or close variations) have been asked a thousand times. I really spent a few hours looking in the obvious and the not-so-obvious places, but there may be something small I'm missing.
让我更清楚地定义问题:我正在编写一个时事通讯应用程序,我希望实际发送过程是异步的.例如,用户单击发送",请求立即返回,然后他们可以检查特定页面中的进度(例如通过 AJAX).它是用传统的 LAMP 堆栈编写的.
Let me define the problem more clearly: I'm writing a newsletter app in which I want the actual sending process to be async. As in, user clicks "send", request returns immediately and then they can check the progress in a specific page (via AJAX, for example). It's written in your traditional LAMP stack.
在我使用的特定主机中,出于安全原因,PHP 的 exec() 和 system() 被禁用,但 Perl 的系统函数(exec、system 和反引号)没有.所以我的 workaround 解决方案是在 Perl 中创建一个触发"脚本,通过 PHP CLI 调用实际的发送者,并重定向到进度页面.
In the particular host I'm using, PHP's exec() and system() are disabled for security reasons, but Perl's system functions (exec, system and backticks) aren't. So my workaround solution was to create a "trigger" script in Perl that calls the actual sender via the PHP CLI, and redirects to the progress page.
截至目前,发件人的电话所在的那一行:
The very line the calls the sender is, as of now:
system("php -q sender.php &");
问题是,它不是立即返回,而是等待脚本完成.我希望它在后台运行并让系统调用本身立即返回.我还尝试在我的 Linux 终端中运行一个类似的脚本,实际上直到脚本完成后才会显示提示,即使我的测试输出没有运行,表明它确实在后台运行.
Problem being, it's not returning immediately, but waiting for the script to finish. I want it to run in the background and have the system call itself return right away. I also tried running a similar script in my Linux terminal, and in fact the prompt doesn't show until after the script has finished, even though my test output doesn't run, indicating it's really running in the background.
- Perl 的 exec() 函数 - 与 system() 的结果相同.
- 将命令更改为:php -q sender.php | at now"),希望at"守护进程能够返回,并且 PHP 进程本身不会附加到 Perl.
- 间接"执行命令:/bin/sh -c 'php -q sender.php &'" - 仍然等到 sender.php 完成发送.
- fork()'ing 进程并在子进程中执行系统调用(希望是分离的进程) - 结果与上述相同
为了确保我没有遗漏任何明显的东西,我创建了一个 sleeper.php 脚本,它在退出前只休眠五秒钟.还有一个像这样的 test.cgi 脚本,逐字逐句:
Just to be sure that I'm not missing anything obvious, I created a sleeper.php script which just sleeps five seconds before exiting. And a test.cgi script that is like this, verbatim:
#!/usr/local/bin/perl
system("php sleeper.php &");
print "Content-type: text/html
done";
我现在应该尝试什么?
推荐答案
基本上你需要守护"一个进程——分叉出一个子进程,然后完全断开它与父进程的连接,这样父进程就可以安全地终止而不影响孩子.
Essentially you need to 'daemonize' a process -- fork off a child, and then entirely disconnect it from the parent so that the parent can safely terminate without affecting the child.
您可以使用 CPAN 模块轻松做到这一点Proc::Daemon:
You can do this easily with the CPAN module 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();
相关文章