2014-01-18 48 views
1

我正在使用Ubuntu 12上的nginx上运行的PHP网站,它可以在后台启动长时间运行的作业。为什么在后台运行PHP进程会导致整个站点挂起?

这个想法是,用户提交一个表单,它在另一个进程中启动一个长时间的工作(php_fpm应该处理这个问题),并且如果作业开始或者没有,立即向用户返回成功/失败消息。

也许这是不是做的最好的方法,但是这是我在做什么:

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

($这个 - > ID和ARG2都是简单的字符串配置工作。)

作业启动并正常运行,但面向前方的网站会挂起直到作业完成。页面无法加载,并且服务器在长时间工作完成之前不会响应。我并不期待这一点。为何会发生这种情况?

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

如果它的事项,这是时显示的默认nginx的错误页面:

您正在查找的页面暂时不可用。

请稍后再试。

+3

内置会话save_handler将锁定会话文件,直到该过程完成并且下一个进程需要等待,直到会话文件解锁。因此,如果您正在使用会话,则可能需要在启动长时间运行的作业之前调用session_write_close。 –

+0

@AlexandruG。我确实在使用会话。从来没有想到这一点。当我有机会并且回报时,我会尝试的! – Matt

+0

@AlexandruG。不幸的是,使用'session_write_close()不会停止等待。但是,似乎只能从我开始工作的计算机上挂起。所以我想知道是否仍然存在会话问题......或者是nginx/php-fpm做了些什么... – Matt

回答

1

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

关于该命令的执行方法,我会用nohup的做到这一点,是这样的:

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

这样你$cmd将在背景和当前的进程中开始可以继续他的执行,而不关心它。

+0

我觉得这是正确的轨道,我已经对我的代码进行了修改,但不幸的是,该网站仍然挂起。虽然我的问题见我的更新。 – Matt

+0

您是否检查过error_log?您很可能会找到有关导致错误的附加信息。 –

0

像这样的事情发生在我身上的时候,在nginx的和PHP FPM,我有PHP运行是这样的:

exec("nohup ssh long-running command & >$logfile 2>&1"); 

我可以看到进程ps axfw这样的:

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

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

% 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 

这意味着子ssh的两个文件描述符以某种方式被挂钩,以便在管道上写入父项。他们是1 - 标准输出 - 和6 - 猜测这是远程命令的标准输出。

因此很显然,在尝试将该stdout重定向到日志文件时发生了错误。解决的办法是使用更习惯shell语法:

exec("nohup ssh long-running command >$logfile 2>&1 &"); 

这样一来,通过exec()分叉壳重定向所有的输出,并把SSH进程在后台在本地机器上,而不是(显然)通过与符号到它。

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异步调用来等待这个页面的响应。

相关问题