[英]php long running process with 'at' acting very strangely
首先,我遠離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 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;
在等待工作重新安排2分鍾后,我得到新工作的內容,除了:
SHLVL = 764已成為SHLVL = 765
更多信息!
正如用戶建議我嘗試使用nohup而不是at。 所以我做的是以下內容:
生成由.h文件中的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日志嗎?
這應該花很少的時間,男孩是我錯了....
由於您的示例中的“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包裝器,以簡化。
我假設您在at -l
運行at -l
以root用戶身份登錄(或者uid PHP在Web服務器中運行),並且作業與在Web服務器中運行的uid PHP相關聯?
但是,其他人可能正在訪問該網頁,因為新的作業以與初始運行的延遲相同的間隔添加,這讓我認為Update.php可能會調用命令再次運行自己?
除了使用“at -l”檢查隊列外,還可以嘗試使用“at -c [ID]”來查看AT將要運行的實際命令。 我認為這有助於診斷錯誤是什么。
我非常懷疑at命令正在運行,因此它每2分鍾重新安排一次。
如果你查看/ var / spool / at / atjobs,你會發現一個類似於此的.SEQ和文件
-rwx------ 1 sergio at 5077 may 3 17:53 a000010153c71d
此文件包含所有環境變量以及atd執行的命令。 希望這可以幫助
首先嘗試:正如其他人所說, LaunchUpdates.php
(你從瀏覽器調用)必須自己調用。 它可能不會在您報告和打算時調用.../Update.php
,但是... /LaunchUpdates.php
。 制造和忽視這一點很容易,所以我的錢就在那里。 [編輯:那不是問題。]
第二次嘗試:既然你已經添加了生成at
腳本,我們可以看到你確實調用了Update.php
。 下一個線索:子shell通常將變量SHLVL
增加到比其父值更多的值。 它超越一位數是非常不尋常的,在這種情況下,它表明你有一個超過700個命令鏈,每個命令由前一個啟動。 這排除了LaunchUpdates.php
以某種方式通過http運行,因為SHLVL
將被重置為比apache中的值多一個。
我的新猜測: Update.php
以某種方式執行$SCRIPT_NAME
或$SCRIPT_FILENAME
,它們(正如我們在生成的腳本中看到的)由at
設置為LaunchUpdates.php
而不是Update.php
。 您可以通過將其替換為空文件或使用僅將消息寫入文件的存根來檢查問題是否在Update.php
:問題應該消失。
最可能的原因是那些環境設置。 如果您無法弄清楚,請向我們展示Update.php
的代碼(以簡化形式,但請確保問題仍然存在),所以我們都可以看看。
編輯2:所以你已經確認正在重新啟動LaunchUpdates.php。 由於它不會調用自身,因此必須由Update.php
。
該文章的作者編寫了以下代碼來實現調度:
print `echo /usr/bin/php -q longThing.php | at now`;
使用反引號使腳本顯示調度命令的結果。 這可能會給你一個提示,如果at
給出任何意外的輸出...也許添加2>&1
以查看是否有任何錯誤。
與“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();
要運行代碼,您將使用相同的命令只刪除“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不是一個選項,請忽略它。
您應該立即啟動您的腳本+ 2分鍾創建並附加日志文件,例如:
file_put_contents(__FILE__.'.log', date('c') . "\n", FILE_APPEND);
然后你可以輕松檢查發生了什么。 兩分鍾的差異讓我們假設它重新進入了自己。
嘗試這個:
exec('/home/user/batchProcess.sh >> ~/process.out 2>&1 | at now &');
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.