为什么在后台运行PHP进程会导致整个站点挂起?

时间:2014-01-18 17:31:31

标签: nginx background-process php

我正在开发一个在Ubuntu 12上运行nginx的PHP站点。它可以在后台启动长时间运行的作业。

这个想法是用户提交一个表单,它在另一个进程中启动一个很长的作业(php_fpm应该处理这个),如果作业已经开始,则会立即向用户返回成功/失败消息。 / p>

也许这不是最好的方法,但这就是我正在做的事情:

`php $docroot/longjob.php $this->ID arg2 &> error_log &`;

($ this-> ID和arg2是用于配置作业的简单字符串。)

作业启动并正常运行,但正面的站点会挂起,直到作业完成。在长作业完成之前,页面不会加载,服务器也不会响应。我没想到这个。为什么会发生这种情况?

更新:所以,我一直在尝试......不幸的是关闭会话处理程序并尝试nohop命令并没有停止挂起。但它只为我挂起,在我发起请求的机器上。我可以从我的手机登录,网站正常工作,也可以为其他用户(phew)。还有其他任何想法,为什么它只会挂起发起请求的机器?

如果重要,这是显示的默认nginx错误页面:

  

您要查找的页面暂时无法使用。

     

请稍后再试。

3 个答案:

答案 0 :(得分:1)

这是因为当前的PHP进程在继续之前等待您执行的命令完成。就像我在之前的评论中所说的那样,在开始该工作之前关闭任何会话,因为PHP将锁定会话文件,直到长时间运行的进程完成,下一个进程需要等到会话文件解锁。

关于执行该命令的方法,我将使用nohup执行此操作,如下所示:

<?php
$cmd = "php $docroot/longjob.php $this->ID arg2";
exec("/usr/bin/nohup $cmd >/dev/null 2>&1 &");

这样你的$cmd将在后台启动,当前进程可以继续执行而无需关心它。

答案 1 :(得分:0)

当我在nginx和PHP FPM下运行PHP时,发生了类似这样的事情:

self.inputViewConstraint.active = false
self.inputViewWithErrorConstraint.active = false
self.inputViewConstraint.active = result == NBValidationResultOK
self.inputViewWithErrorConstraint.active = !self.inputViewConstraint.active

我可以在exec("nohup ssh long-running command & >$logfile 2>&1"); 中看到这样的流程:

ps axfw

一些调试显示FPM卡在等待命令:

[...]
18658 ?        S      0:00  \_ php-fpm: pool www
18734 ?        Z      0:00  |   \_ [sh] <defunct>
[...]
18737 ?        S      0:00 ssh long-running command

这意味着子ssh的两个文件描述符不知何故被钩住以将管道写入父级。它们是1 - 标准输出 - 并且6 - 猜测远程命令的标准输出。

很明显,在尝试将该stdout重定向到日志文件时出现问题。解决方案是使用更通常的shell语法:

% sudo strace -p 18658
Process 18658 attached
read(9, 

% sudo lsof -p 18658 | grep 9r
php5-fpm 18658  user    9r  FIFO                0,8      0t0 9332553 pipe

% sudo lsof -n | grep 9332553
php5-fpm  18658        user     9r     FIFO                0,8        0t0    9332553 pipe
ssh       18737        user     1w     FIFO                0,8        0t0    9332553 pipe
ssh       18737        user     6w     FIFO                0,8        0t0    9332553 pipe

这样, exec("nohup ssh long-running command >$logfile 2>&1 &"); 分叉的shell重定向了所有输出并将ssh进程放在本地机器的后台,而不是(显然)将&符号传递给它。

答案 2 :(得分:0)

对于冗长的[后台]进程,我将这个技巧用于我的服务器。 只需等待几秒钟,然后可以正常浏览其他页面。

希望有人能帮到你。

session_start();
isset($_SESSION['id']) or header('Location: ./index.html'.(
    isset($_REQUEST['redir'])? '?redir='.urlencode($_REQUEST['redir']):NULL
),TRUE)&exit;

$data= $_SESSION['userdata'];

/**The session need to be closed when running long process***/
session_write_close() & ignore_user_abort(TRUE);
set_time_limit(0);

大多数时候我使用AJAX异步调用来等待来自此页面的响应。