简体   繁体   English

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

[英]php long running process with 'at' acting very strangely

Firstly, I am far from a Linux expert so that might be the issue here, but anyway, to the problem: 首先,我远离Linux专家,所以这可能是问题,但无论如何,问题是:

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

to launch a long-running PHP process. 启动一个长期运行的PHP进程。 This works flawlessly in my MAMP config on my Mac. 这在我的Mac上的MAMP配置中完美无瑕。 However once I deployed it to our VPS I got some really weird results. 然而,一旦我将它部署到我们的VPS,我得到了一些非常奇怪的结果。

So first I do a simple test, using an SSH connection: 首先,我使用SSH连接进行简单的测试:

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

The result: 结果:

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

and indeed, 2 minutes later the php script is executed. 事实上,2分钟后执行php脚本。 So far so good. 到现在为止还挺好。

Next I try the following approach: 接下来我尝试以下方法:

in my browser I open: 在我的浏览器中我打开:

www.myserver.com/Update/LaunchUpdates.php

this php script contains the line: 这个php脚本包含以下行:

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

What happens is the following: I check with at -l the state and I see: 会发生以下情况:我在-l处检查状态,我看到:

job 2304 at 2012-04-29 19:32

Then I wait 2 minutes and run at -l again. 然后我等了2分钟再次跑到-l。 I expect to see an empty result but instead I get: 我希望看到一个空的结果,但我得到:

job 2305 at 2012-04-29 19:34

and 2 minutes later I get 2分钟后我得到了

job 2306 at 2012-04-29 19:36

I haven't got the slightest idea of what is going on there. 我对那里发生的事情一无所知。 The php script is not executed and the job seems to reschedule itself 2 minutes later. PHP脚本没有执行,工作似乎在2分钟后重新安排。 And this goes on and on until i atrm the job. 这种情况一直持续到我工作为止。

Does anyone know what might be going on? 有谁知道可能会发生什么?

Some more info: 更多信息:

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

Some more details. 更多细节。 Here is the content of the at job when it is scheduled: (at -c [ID]) 以下是at job安排时的内容:( 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;

When waiting for the job to reschedule after 2 minutes I get the new job's contents and it is identical except for: 在等待工作重新安排2分钟后,我得到新工作的内容,除了:

SHLVL=764 that has become SHLVL=765 SHLVL = 764已成为SHLVL = 765

More info! 更多信息!

As a user suggested I tried using nohup instead of at. 正如用户建议我尝试使用nohup而不是at。 So what I did was the following: 所以我做的是以下内容:

Generate the command to be run by nohup in a .sh file (with execute permissions). 生成由.h文件中的nohup运行的命令(具有执行权限)。 and then do exec('nohup .....') 然后做exec('nohup .....')

I also added a check in LaunchUpdates to make sure it is not called again before the nohup batch has done running (I basically rm the .sh file and the end of its batch, and in LaunchUpdates I check for the existence of that file). 我还在LaunchUpdates中添加了一个检查,以确保在nohup批处理完成之前不再调用它(我基本上是.sh文件和批处理的结尾,而在LaunchUpdates中我检查是否存在该文件)。

So in short. 所以简而言之。

batchProcess.sh contains: batchProcess.sh包含:

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

my LaunchUpdates php code contains: 我的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 &');

No what happens: 没有发生什么:

I comment out the exec line in my php script so the file does not get executed but generated. 我在我的php脚本中注释掉exec行,所以文件没有被执行但是生成了。 I test the file by hand by logging in with ssh, change to user "user" and run: 我通过使用ssh登录手动测试文件,更改为用户“user”并运行:

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

all works fine (and the .sh file is deleted at the end)! 一切正常(最后删除.sh文件)!

Next I uncomment the exec line and rerun the php script. 接下来,我取消注释exec行并重新运行php脚本。 process.out contains: process.out包含:

Process still running. Try again later!

This means that it IS executing the base-script again and not the exec statement??? 这意味着它再次执行基本脚本而不是exec语句??? I am COMPLETELY lost here! 我完全迷失在这里! Since on both accounts I run the same bash script there can be no error as to what commands get executed. 因为在这两个帐户上我运行相同的bash脚本,所以执行什么命令都没有错误。

Should I start digging in the apache logs? 我应该开始挖掘apache日志吗?

This was supposed to take little time, boy was I wrong .... 这应该花很少的时间,男孩是我错了....

Since the "at" command in your example is used to unbind the script from the calling terminal you could use "nohup" instead of "at". 由于您的示例中的“at”命令用于从主叫终端取消绑定脚本,因此您可以使用“nohup”而不是“at”。

Try this one (unbind from the calling process, wait 120 secs and call php): 尝试这个(从调用进程解除绑定,等待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

It creates the/tmp/longphp.log file for analysis. 它创建/ tmp / longphp.log文件以进行分析。 You could also create a shell wrapper containing the previous script, to simplify. 您还可以创建包含前一个脚本的shell包装器,以简化。

I assume you are logged in as root (or the uid PHP runs as in the webserver) when running at -l , and that the jobs are associated with the uid PHP runs as in the webserver ? 我假设您在at -l运行at -l以root用户身份登录(或者uid PHP在Web服务器中运行),并且作业与在Web服务器中运行的uid PHP相关联?

It is possible that someone else is accessing the webpage, however, since new jobs are being added at the same interval as the delay for the initial run makes me think that Update.php might be calling the command to run itself again? 但是,其他人可能正在访问该网页,因为新的作业以与初始运行的延迟相同的间隔添加,这让我认为Update.php可能会调用命令再次运行自己?

Besides using "at -l" to check the queue, also try using "at -c [ID]" to see the actual command that AT will be running. 除了使用“at -l”检查队列外,还可以尝试使用“at -c [ID]”来查看AT将要运行的实际命令。 I think that will help diagnose what the error is. 我认为这有助于诊断错误是什么。

I highly suspect that the at command is running itself, so it is rescheduling itself every 2 minutes. 我非常怀疑at命令正在运行,因此它每2分钟重新安排一次。

If you look at /var/spool/at/atjobs you will find a .SEQ and file(s) similar to this 如果你查看/ var / spool / at / atjobs,你会发现一个类似于此的.SEQ和文件

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

This file has all the environment vars and also the command that atd executes. 此文件包含所有环境变量以及atd执行的命令。 Hope this helps 希望这可以帮助

First try: As others said, LaunchUpdates.php (which you call from the browser) must be invoking itself. 首先尝试:正如其他人所说, LaunchUpdates.php (你从浏览器调用)必须自己调用。 It probably does not invoke .../Update.php as you report and intend, but ... /LaunchUpdates.php . 它可能不会在您报告和打算时调用.../Update.php ,但是... /LaunchUpdates.php An easy mistake to make, and to overlook, so my money is on that. 制造和忽视这一点很容易,所以我的钱就在那里。 [Edit: That was not the problem.] [编辑:那不是问题。]

Second try: Now that you've added the generated at script, we can see that you do in fact call Update.php . 第二次尝试:既然你已经添加了生成at脚本,我们可以看到你确实调用了Update.php Next clue: A subshell normally increments the variable SHLVL to one more than the value of its parent. 下一个线索:子shell通常将变量SHLVL增加到比其父值更多的值。 It is extremely unusual for it to go beyond single digits, and in this case it shows that you've got a chain of more than 700 at commands, each launched by the previous one. 它超越一位数是非常不寻常的,在这种情况下,它表明你有一个超过700个命令链,每个命令由前一个启动。 This rules out LaunchUpdates.php somehow being run via http, since SHLVL would then be reset to one more than its value in apache. 这排除了LaunchUpdates.php以某种方式通过http运行,因为SHLVL将被重置为比apache中的值多一个。

My new guess: Update.php is somehow executing $SCRIPT_NAME or $SCRIPT_FILENAME , which (as we can see in the generated script) are set by at to LaunchUpdates.php instead of Update.php . 我的新猜测: Update.php以某种方式执行$SCRIPT_NAME$SCRIPT_FILENAME ,它们(正如我们在生成的脚本中看到的)由at设置为LaunchUpdates.php而不是Update.php You can check that the problem is in Update.php by replacing it with an empty file, or with a stub that just writes out a message to a file: the problem should disappear. 您可以通过将其替换为空文件或使用仅将消息写入文件的存根来检查问题是否在Update.php :问题应该消失。

Most likely the cause are those environment settings. 最可能的原因是那些环境设置。 If you can't figure it out, show us the code for Update.php (in simplified form, but make sure the problem is still present) so we can all take a look. 如果您无法弄清楚,请向我们展示Update.php的代码(以简化形式,但请确保问题仍然存在),所以我们都可以看看。

Edit 2: So you've confirmed that LaunchUpdates.php is being re-launched. 编辑2:所以你已经确认正在重新启动LaunchUpdates.php。 Since it doesn't call itself, it must be called by Update.php . 由于它不会调用自身,因此必须由Update.php

The author of the article wrote the following code to effect the scheduling: 该文章的作者编写了以下代码来实现调度:

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

Making the script show the results of the scheduling command using backticks. 使用反引号使脚本显示调度命令的结果。 This might give you a hint if at is giving any unexpected output ... perhaps add 2>&1 to see if there were any errors. 这可能会给你一个提示,如果at给出任何意外的输出...也许添加2>&1以查看是否有任何错误。

Not so much an answer to the "at" issue but as an alternative you could setup a timeout to run in 2 minutes using the prggmr library that will execute the code contained in the Update.php file. 与“at”问题的答案不同,但作为替代方案,您可以使用将执行Update.php文件中包含的代码的prggmr库设置超时,以便在2分钟内运行。

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();

To run the code you would use the same command only drop the "at" 要运行代码,您将使用相同的命令只删除“at”

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

This would run the code within that timeout in 2 minutes and kill the script automatically afterwords, note that the library requires PHP 5.4 to run and again this is only a thought as an alternative, if installing 5.4 is not an option just ignore this. 这将在2分钟内在该超时内运行代码并在自动后自动终止脚本,请注意该库需要运行PHP 5.4并且这只是一种考虑,如果安装5.4不是一个选项,请忽略它。

You should make your script you launch at now + 2 minutes creating and appending a logfile, eg: 您应该立即启动您的脚本+ 2分钟创建并附加日志文件,例如:

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

Then you can easily check what happens. 然后你可以轻松检查发生了什么。 The two minute difference let one assume that it re-shedules itself. 两分钟的差异让我们假设它重新进入了自己。

尝试这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM