exec('command args > /log/file &'); を使用する PHP スクリプトがあります。ループ内で、同時に実行される複数の子スクリプトを作成します。基本的に、親スクリプトはデータベースからユーザー情報を取得し、並行して実行される子スクリプトを作成します。その後、子スクリプトは、1 人のユーザーに送信する電子メールを作成します。これは約 50,000 回発生します。
50,000 の同時実行プロセスの作成を防ぐために、現在実行中のプロセスを追跡するデータベース テーブルがあり、新しいプロセスを作成する前に、親は現在の子の数をチェックし、25 の子が現在アクティブな場合はスリープします。子はタスクを完了すると、テーブル内の行を削除し、親を解放してさらに子を作成できるようにします。
問題は、exec コマンドの約 10% が警告なしに失敗することです。理由はないようです。親スクリプトをもう一度実行できます (同じユーザーに 2 回メールを送信しないようにするのは賢明です)。前回失敗したのと同じ exec コマンドを使用して、90% の確率で動作します。スクリプトを 5 ~ 6 回続けて実行すると、全員にメールが送信されます。
実行の直後にスリープを入れることで、成功率を 95% 程度まで上げることができます。
同じコマンドが後で機能する場合、exec が失敗するのはなぜですか? 完了するまでスクリプトを繰り返し続けることはできますが、実行の問題を解決したいと考えています。
いくつかの非常に単純化されたサンプル コード:
親スクリプト:
do {
//get user, group, and supergroup information for users that haven't
//been emailed yet
foreach ($users as $userArray) {
$processId = insertIntoProcessQueue($userArray);
$cmd = 'sudo php -q ./childScript.php ' . cliArg($userArray) . ' ' .
cliArg($groupArray) . ' ' . cliArg($supergroupArray)
' ' . $proccessId . ' > file.log &';
exec($cmd);
do {
if (numChildren() >= 25) {
sleep(1);
$waiting = true;
}
} while ($waiting);
}
$incomplete = moreUsersToEmail() > 0 ? true : false;
} while ($incomplete);
function cliArg($array) {
return escapeshellarg(json_encode($arg));
}
子スクリプト:
ignore_user_abort(true);
$user = json_decode($argv[1]);
$group = json_decode($argv[2]);
$supergroup = json_decode($argv[3]);
print_r($user);
$email = createEmail($user, $group, $supergroup);
$email->sendEmail();
removeFromProcessQueue($argv[4]);
flush();
exit;
print_r は、スクリプトが完了したときにのみログ ファイルに表示され、エラーが発生することはないため、失敗の理由に関するデータを取得できません。それに加えて、個々のユーザーで一貫して失敗することはなく、一度に 1 人のユーザーを実行しても失敗しないため、すべてのユーザーに対してスクリプトを実行し、45,000 のエラーの中からエラーをキャッチする必要があります。正常に動作しています。また、親と子は子を開始する親を超えて通信することはないため、子がいつ失敗したかを (親から) 検出することはできません (そうでない場合は、後で親を再実行する代わりに、失敗した子をすぐに再試行して開始することができます)。 )。
編集:したがって、動的に生成され、使用されるたびに破棄および再生成される組み込みスクリプトがあることがわかりました(理由は聞かないでください)。これにより、プロセスを並行して実行しているときに競合状態が発生し、スクリプトが失敗します。
残念ながら無駄な時間をありがとうございました。