10

まず、私は 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");

何が起こるかは次のとおりです。 at -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 ジョブの内容は次のとおりです: (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 になりました

より詳しい情報!

ユーザーが提案したように、at の代わりに nohup を使用してみました。だから私がしたことは次のとおりでした:

nohup によって実行されるコマンドを .sh ファイルに生成します (実行権限あり)。そして exec('nohup .....') を実行します

また、LaunchUpdates にチェックを追加して、nohup バッチの実行が完了する前に再度呼び出されないようにしました (基本的に .sh ファイルとそのバッチの最後を rm し、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 ログを調べ始めるべきですか?

これには少し時間がかかるはずでしたが、少年は私が間違っていました....

4

9 に答える 9

3

例の「at」コマンドは、呼び出し元の端末からスクリプトをアンバインドするために使用されるため、「at」の代わりに「nohup」を使用できます。

これを試してください (呼び出しプロセスからバインドを解除し、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 ファイルを作成します。簡単にするために、前のスクリプトを含むシェル ラッパーを作成することもできます。

于 2012-05-03T15:55:11.017 に答える
2

実行時に root としてログインしている (または uid PHP が Web サーバーのように実行されている) と仮定at -lし、ジョブは uid PHP が Web サーバーのように実行されていると関連付けられていると仮定します。

他の誰かが Web ページにアクセスしている可能性がありますが、最初の実行の遅延と同じ間隔で新しいジョブが追加されているため、Update.php がコマンドを呼び出して自分自身を再度実行していると思いますか?

于 2012-05-03T11:48:49.907 に答える
2

「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 をインストールするオプションがない場合は、これを無視してください。

于 2012-05-09T18:09:28.380 に答える
2

/var/spool/at/atjobs を見ると、次のような .SEQ とファイルが見つかります。

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

このファイルには、すべての環境変数と、atd が実行するコマンドが含まれています。お役に立てれば

于 2012-05-03T16:00:04.987 に答える
2

この記事の著者は、スケジューリングを行うために次のコードを書きました。

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

バックティックを使用して、スケジュール コマンドの結果をスクリプトに表示させる。atこれにより、予期しない出力が得られた場合にヒントが得られる可能性があります...おそらく追加2>&1して、エラーがあったかどうかを確認します。

于 2012-05-09T14:52:40.613 に答える
2

最初の試行:他の人が言ったように、LaunchUpdates.php(ブラウザから呼び出す) は自分自身を呼び出している必要があります。.../Update.phpご報告、意図したとおりには発動しないでしょうが・・・... /LaunchUpdates.php。犯したり見落としたりしやすい間違いなので、私のお金はそれにあります。[編集: それは問題ではありませんでした。]

2 回目の試行:生成されたスクリプトを追加したのでat、実際に を呼び出していることがわかりますUpdate.php。次の手がかり: サブシェルは通常、変数SHLVLをその親の値よりも 1 つ大きくします。1 桁を超えることは非常にまれであり、この場合、700 を超える at コマンドのチェーンがあり、それぞれが前のコマンドによって起動されていることを示しています。これにより、LaunchUpdates.php何らかの方法で http 経由で実行されることが除外されます。これSHLVLは、apache の値よりも 1 大きい値にリセットされるためです。

私の新しい推測:Update.php何らかの形で$SCRIPT_NAMEorを実行$SCRIPT_FILENAMEしており、(生成されたスクリプトでわかるように)の代わりにattoによって設定されています。空のファイルに置き換えるか、メッセージをファイルに書き出すだけのスタブに置き換えることで、問題が発生していることを確認できます。問題は消えるはずです。LaunchUpdates.phpUpdate.phpUpdate.php

ほとんどの場合、これらの環境設定が原因です。わからない場合は、Update.php(簡略化された形式で、ただし問題がまだ存在することを確認してください)のコードを見せてください。

編集 2: LaunchUpdates.php が再起動されていることを確認しました。それ自体を呼び出さないため、 によって呼び出される必要がありますUpdate.php

于 2012-05-06T09:05:53.830 に答える
2

「at -l」を使用してキューをチェックする以外に、「at -c [ID]」を使用して、AT が実行する実際のコマンドを確認してみてください。エラーが何であるかを診断するのに役立つと思います。

at コマンド自体が実行されている可能性が非常に高いため、2 分ごとに再スケジュールされています。

于 2012-05-03T13:22:58.277 に答える
1

今すぐ起動するスクリプトを、ログファイルの作成と追加に 2 分追加する必要があります。

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

その後、何が起こるかを簡単に確認できます。2 分の違いは、それ自体を再スケジュールすることを前提としています。

于 2012-05-03T15:35:47.543 に答える
1

これを試して:

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

于 2012-05-10T00:55:41.137 に答える