php长时间运行的过程与'at'表现得非常奇怪

时间:2012-04-29 21:29:59

标签: php linux gentoo

首先,我远离Linux专家,所以这可能是问题,但无论如何,问题是:

我按照这里写的内容:http://symcbean.blogspot.com/2010/02/php-and-long-running-processes.html

启动一个长期运行的PHP进程。这在我的Mac上的MAMP配置中完美无瑕。然而,一旦我将它部署到我们的VPS,我得到了一些非常奇怪的结果。

首先,我使用SSH连接进行简单的测试:

echo '/usr/local/php53/bin/php -d memory_limit=512M -q /home/user/www/Update/Update.php;' | at now + 2minutes

结果:

warning: commands will be executed using /bin/sh
job 2300 at 2012-04-29 19:24

确实,2分钟后执行php脚本。到目前为止一切都很好。

接下来,我尝试以下方法:

在我的浏览器中打开:

www.myserver.com/Update/LaunchUpdates.php

这个php脚本包含以下行:

exec("echo '/usr/local/php53/bin/php -d memory_limit=512M -q /home/user/www/Update/Update.php;' | at now + 2minutes");

以下是: 我检查了-l状态,我看到了:

job 2304 at 2012-04-29 19:32

然后我等了2分钟再次跑到-l。我希望看到一个空的结果,但我得到:

job 2305 at 2012-04-29 19:34

2分钟后我得到

job 2306 at 2012-04-29 19:36

我对那里发生的事情一无所知。 PHP脚本没有执行,工作似乎在2分钟后重新安排。这种情况一直持续到我工作为止。

有谁知道可能会发生什么?

更多信息:

cat /etc/*-release
Gentoo Base System version 1.6.14

更多细节。以下是安排工作时的内容:( at -c [ID])

#!/bin/sh
# atrun uid=1002 gid=100
# mail user 1
umask 33
SERVER_SIGNATURE=\<address\>Apache/2.2.20\ \(Unix\)\ mod_ssl/2.2.20\ OpenSSL/0.9.8o\ Server\ at\ xxx.yyyyy.com\ Port\ 80\</address\>"
"; export SERVER_SIGNATURE
HTTP_USER_AGENT=Mozilla/5.0\ \(Macintosh\;\ Intel\ Mac\ OS\ X\ 10_7_3\)\ AppleWebKit/534.55.3\ \(KHTML,\ like\ Gecko\)\ Version/5.1.5\ Safari/534.55.3; export HTTP_USER_AGENT
HTTP_HOST=xxx.yyyyy.com; export HTTP_HOST
SERVER_PORT=80; export SERVER_PORT
DOCUMENT_ROOT=/home/user/www; export DOCUMENT_ROOT
SCRIPT_FILENAME=/home/user/www/Update/LaunchUpdates.php; export SCRIPT_FILENAME
REQUEST_URI=/Update/LaunchUpdates.php; export REQUEST_URI
SCRIPT_NAME=/Update/LaunchUpdates.php; export SCRIPT_NAME
HTTP_CONNECTION=keep-alive; export HTTP_CONNECTION
REMOTE_PORT=36291; export REMOTE_PORT
PATH=/bin:/usr/bin; export PATH
PWD=/home/user/www/Update; export PWD
SERVER_ADMIN=webmaster@abcdef.com; export SERVER_ADMIN
REDIRECT_STATUS=200; export REDIRECT_STATUS
HTTP_ACCEPT_LANGUAGE=en-us; export HTTP_ACCEPT_LANGUAGE
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml\;q=0.9,\*/\*\;q=0.8; export HTTP_ACCEPT
REMOTE_ADDR=83.101.41.41; export REMOTE_ADDR
SHLVL=764; export SHLVL
SERVER_NAME=xxx.yyyyy.com; export SERVER_NAME
SERVER_SOFTWARE=Apache/2.2.20\ \(Unix\)\ mod_ssl/2.2.20\ OpenSSL/0.9.8o; export SERVER_SOFTWARE
QUERY_STRING=; export QUERY_STRING
SERVER_ADDR=1.2.3.4; export SERVER_ADDR
GATEWAY_INTERFACE=CGI/1.1; export GATEWAY_INTERFACE
SERVER_PROTOCOL=HTTP/1.1; export SERVER_PROTOCOL
HTTP_ACCEPT_ENCODING=gzip,\ deflate; export HTTP_ACCEPT_ENCODING
REQUEST_METHOD=GET; export REQUEST_METHOD
cd /home/user/www/Update || {
     echo 'Execution directory inaccessible' >&2
     exit 1
}
/usr/local/php53/bin/php -d memory_limit=512M -q /home/user/www/Update/Update.php;

等待工作在2分钟后重新安排时,我得到新工作的内容,除了:

之外它是相同的

SHLVL = 764已成为SHLVL = 765

更多信息!

正如用户建议我尝试使用nohup而不是at。所以我做的是以下内容:

在.sh文件中生成nohup运行的命令(具有执行权限)。然后做exec('nohup .....')

我还在LaunchUpdates中添加了一个检查,以确保在nohup批处理完成之前不再调用它(我基本上是.sh文件及其批处理的结尾,在LaunchUpdates中我检查是否存在文件)。

简而言之。

batchProcess.sh包含:

/usr/local/php53/bin/php -d memory_limit=512M -q /home/user/www/Update/Update.php; 
rm /home/user/batchProcess.sh

我的LaunchUpdates php代码包含:

$batchFile = "/home/user/batchProcess.sh";

if (file_exists($batchFile))
{
    echo 'Process still running. Try again later!';
    exit;
}

exec('nohup /home/user/batchProcess.sh > ~/process.out 2> ~/process.err < /dev/null &');

不会发生什么:

我在我的php脚本中注释掉了exec行,所以文件没有被执行但是生成了。 我通过使用ssh登录手动测试文件,更改为用户“user”并运行:

nohup /home/user/batchProcess.sh > ~/process.out 2> ~/process.err < /dev/null &

一切正常(最后删除.sh文件)!

接下来,我取消注释exec行并重新运行php脚本。 process.out包含:

Process still running. Try again later!

这意味着它再次执行基本脚本而不是exec语句??? 我完全迷失在这里!因为在两个帐户上我运行相同的bash脚本,所以执行什么命令都没有错误。

我应该开始挖掘apache日志吗?

这应该花很少的时间,男孩我错了......

9 个答案:

答案 0 :(得分:3)

由于您的示例中的“at”命令用于从主叫终端取消绑定脚本,因此您可以使用“nohup”而不是“at”。

尝试这个(从调用进程解除绑定,等待120秒并调用php):

/usr/bin/nohup /bin/sleep 120 2> /dev/null && \
/bin/date >> /tmp/longphp.log && \
/usr/local/php53/bin/php -d memory_limit=512M \
  -q /home/user/www/Update/Update.php >> /tmp/longphp.log 2>> /tmp/longphp.log

它创建/ tmp / longphp.log文件以进行分析。 您还可以创建一个包含前一个脚本的shell包装器,以简化。

答案 1 :(得分:2)

我假设您在运行at -l时以root用户身份登录(或者uid PHP在网络服务器中运行),并且作业与网络服务器中运行的uid PHP相关联?

其他人可能正在访问该网页,但是,由于新的作业以与初始运行的延迟相同的间隔添加,因此我认为Update.php可能正在调用命令再次运行自己?

答案 2 :(得分:2)

除了使用“at -l”检查队列外,还可以尝试使用“at -c [ID]”来查看AT将要运行的实际命令。我认为这有助于诊断错误是什么。

我非常怀疑at命令正在运行,所以它每2分钟重新安排一次。

答案 3 :(得分:2)

如果查看/ var / spool / at / atjobs,您会发现.SEQ和与此类似的文件

-rwx------ 1 sergio at   5077 may  3 17:53 a000010153c71d

此文件包含所有环境变量以及atd执行的命令。希望这有帮助

答案 4 :(得分:2)

首先尝试:正如其他人所说,LaunchUpdates.php(您从浏览器调用)必须自行调用。它可能不会在您报告和打算时调用.../Update.php,而是... /LaunchUpdates.php。制造和忽视这一点很容易,所以我的钱就在那里。 [编辑:那不是问题。]

第二次尝试:现在您已添加了生成的at脚本,我们可以看到您确实调用了Update.php。下一个线索:子shell通常会将变量SHLVL增加到比其父值更多的值。它超越一位数是非常不寻常的,在这种情况下,它表明你有一个超过700个命令链,每个命令由前一个启动。这排除LaunchUpdates.php以某种方式通过http运行,因为SHLVL将被重置为比apache中的值多一个。

我的新猜测:Update.php以某种方式执行$SCRIPT_NAME$SCRIPT_FILENAME,(我们在生成的脚本中可以看到)由at设置为{{1}而不是LaunchUpdates.php。您可以通过将其替换为空文件或使用只是将消息写入文件的存根来检查问题是否在Update.php中:问题应该消失。

最有可能的原因是那些环境设置。如果您无法弄清楚,请向我们展示Update.php的代码(以简化形式,但请确保问题仍然存在),以便我们都可以看看。

编辑2:因此您已确认正在重新启动LaunchUpdates.php。由于它不会调用自身,因此必须由Update.php调用。

答案 5 :(得分:2)

该文章的作者编写了以下代码来实现调度:

print `echo /usr/bin/php -q longThing.php | at now`;

使用反引号使脚本显示调度命令的结果。如果at提供任何意外输出,这可能会给您一个提示...也许添加2>&1以查看是否有任何错误。

答案 6 :(得分:2)

不是“at”问题的答案,但作为替代方案,您可以使用prggmr库设置超时,以便在2分钟内运行,该库将执行Update.php文件中包含的代码。< / p>

require 'path/to/prggmr/src/prggmr.php';

prggmr\timeout(function(){
    // Put logic from Update.php HERE
}, 120000);
// note the time is in milliseconds

prggmr\loop();

要运行代码,您将使用相同的命令只删除“at”

exec("echo '/usr/local/php53/bin/php -d memory_limit=512M -q /home/user/www/Update/Update.php;'");

这将在2分钟内在该超时内运行代码并在自动后自动终止脚本,请注意该库需要运行PHP 5.4并且这只是一种考虑,如果安装5.4不是一个选项只是忽略此

答案 7 :(得分:1)

你应该让你现在启动的脚本+ 2分钟创建并附加一个日志文件,例如:

file_put_contents(__FILE__.'.log', date('c') . "\n", FILE_APPEND);

然后你可以轻松检查发生了什么。两分钟的区别让我们假设它重新进行了自我调整。

答案 8 :(得分:1)

试试这个:

exec('/home/user/batchProcess.sh >> ~/process.out 2>&1 | at now &');