Windows バッチ処理


あるPHPファイルをコマンドプロンプトから実行し、長い処理を毎日特定の時間に実行しています。

しかし、処理が重すぎると途中でコマンドプロンプト自体が落ちてしまいます。

そこで質問です。

コマンドプロンプトを監視し、落ちたら指定したバッチファイルを起動する様な処理をWindows上でする事は可能でしょうか?

回答の条件
  • 1人1回まで
  • 13歳以上
  • 登録:2015/08/06 19:36:58
  • 終了:2015/08/09 21:33:42

ベストアンサー

id:TransFreeBSD No.3

TransFreeBSD回答回数664ベストアンサー獲得回数2662015/08/08 11:55:55

ポイント40pt

手法はいくつかあります。

ウォッチドッグ式

LLマンさんの方式です。
組み込みシステムではハード的にウォッチドッグタイマーという、定時間操作しないと再起動などのかかる仕組みがあったりしますが、それのソフト版ですね。
処理進行に合わせ決まった操作を行って、外部から定期的にその操作が行われているか監視するものです。
操作の対象は他のプロセスから確認できるなら何でも良く、ファイルを使っても良いですし、データベースを使う方法もあります。
操作は更新日時を更新するとかで事足りますが、処理の記録、つまりログを残すようにすれば、後々の原因究明に役立つかもしれません。

ロック式

ファイルをロックするなどして、ロックの有無でプロセスの存在を確認する方法です。
排他制御を利用するわけです。
ファイルロックの他にセマフォやミューテックスなど、プロセスに結びついた排他制御なら何でも良いと思いますが、往々にしてOS依存があるのが難点かもしれません。
phpだとsyncというクロスプラットフォームな仕組みがあるらしいです。
他に、データベースのロックを使っても良いと思います。

プロセス監視式

今回の場合、これがよいと思います。
exec()で実行すれば、正常にしろ異常にしろ終了まで待ちます。終了したら出力結果やreturn_varを見て異常終了していないか確認します。
つまり、phpのプログラムを直接実行せず、phpのプログラムを実行し、監視するphpのプログラムを作り、それを実行するということです。
http://webkaru.net/php/function-exec-system/
一番素直な実装だと思います。
また、終了コードを記録しておけば、なぜ強制終了させられたかも分かります。
http://www.hiteksoftware.com/knowledge/articles/049.htm
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms681381(v=vs.85).aspx

今の具体的な手順や処理内容を書いてもらえれば、もう少し具体的な事が書けると思います。

他1件のコメントを見る
id:TransFreeBSD

いくつか問題あったので再コメント

即再実行すれば問題ないのなら下記の様になりますかね。

<?php
ini_set("date.timezone", "Asia/Tokyo");
ini_set("log_errors", 1);
ini_set("error_log", "hoge.log");
for ($i = 1; $i <= 10; $i++) {
    error_log("start script");
    $start = time();
    unset($out, $ret);
    exec('c:\php\php.exe -d "date.timezone=Asia/Tokyo" -d "log_errors" -d "error_log=hoge.log" -d "memory_limit=1073741824" c:\php\hoge.php 2>&1', $out, $ret);
    $stop = time();
    error_log("\n    |" . implode("\n    |", $out));
    error_log("stop script with exit code $ret");
    if ($stop - $start < 3) {
        error_log("waiting about 3 * $i sec.");
        sleep(3 * $i); // 3から30秒まで待ってから再起動
    } else {
        $i = 1; // カウンタはリセットする
    }
}
?>

起動終了と、エラー、念のため標準出力、エラー出力の内容をログファイルに残すようにしてみました。
あと、何らかの原因(例えばデータベース接続に失敗とか)で即エラー終了しているといった場合に、延々と再起動を繰り返さないよう、3秒以内に終了が10回続いたら終了する様にしています。

なお、
> ただ、たまに非常に文章量が大きいテキストを受け取ると、プログラムそのものが落ちます。
ってことでメモリ関連をググると下記のような記事が出てきました。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1266281967
http://php.net/manual/ja/ini.core.php#ini.sect.resource-limits
http://d.hatena.ne.jp/hnw/20100801
デフォルト128Mだそうで、越える可能性はありますね。
設定値はphpinfoで確認できます。
これが原因ならば、この値を変えるか、大きなメールは弾くかした方が良いかもしれません。

2015/08/08 20:44:40
id:webtomake

皆様

親身になってご返答頂き、ありがとうございました。

私の質問内容が良くなく、細部までお伝え出来ておりませんでした。

ただ、ご返答頂いた内容はどれも勉強になるものであり、皆様には感謝しております。

一旦、こちらの回答にて閉じさせていただきます。

2015/08/09 21:33:13

その他の回答(2件)

id:a-kuma3 No.1

a-kuma3回答回数4504ベストアンサー獲得回数18702015/08/06 20:25:41

ポイント30pt

max_execution_time の指定で実行が打ち切られているのではないでしょうか。
処理内容が変わらないのであれば、再起動しても途中で打ち切られるのは変わらないと思います。
max_execution_time を長くしてみてはどうでしょう。

デフォルトの位置にある php.ini を変更したくないのであれば、バッチ処理用の php.ini を用意して、バッチファイルの php.exe の -c オプションで指定すれば良いと思います。

この質問と同じことを聞かれているような気はするのですが、反応がなかったので第三者にはよく分かりません。

他3件のコメントを見る
id:a-kuma3

No.3 のコメントを見て、やっと分かりましたよ。
popen で非同期で実行しちゃうから子プロセスが終了したことが分からない、ってことですね。
メールを待ち続けるだけなら、異常終了かどうかの判定も要らないので、popen で起動しているところを、exec で起動するように変えるだけですね。

2015/08/08 16:02:26
id:a-kuma3

違う。
popen で起動しているところを exec で起動するようにして、起動するところを無限ループにする、ですね。

2015/08/08 16:29:05
id:dev2 No.2

LLマン回答回数67ベストアンサー獲得回数262015/08/06 20:40:37

ポイント30pt

1. A(目的)のプログラムが処理に成功したとき、
何らかのファイルCに記録を残すようにします。

2. Bのプログラムが一定時間後にそのファイルCを読みに行き、
もし記録が残ってないなら、失敗したと判定して、
最初のプログラムAを再実行します。
そしてまた一定時間後に、Cを読みに行きます。

3. 成功した記録があれば、Bのプログラムは何もせず終了します。


プロセスに触らない、これが一番簡単な方法だと思います。
もちろん、再実行で成功する可能性がある場合の話ですが。

id:TransFreeBSD No.3

TransFreeBSD回答回数664ベストアンサー獲得回数2662015/08/08 11:55:55ここでベストアンサー

ポイント40pt

手法はいくつかあります。

ウォッチドッグ式

LLマンさんの方式です。
組み込みシステムではハード的にウォッチドッグタイマーという、定時間操作しないと再起動などのかかる仕組みがあったりしますが、それのソフト版ですね。
処理進行に合わせ決まった操作を行って、外部から定期的にその操作が行われているか監視するものです。
操作の対象は他のプロセスから確認できるなら何でも良く、ファイルを使っても良いですし、データベースを使う方法もあります。
操作は更新日時を更新するとかで事足りますが、処理の記録、つまりログを残すようにすれば、後々の原因究明に役立つかもしれません。

ロック式

ファイルをロックするなどして、ロックの有無でプロセスの存在を確認する方法です。
排他制御を利用するわけです。
ファイルロックの他にセマフォやミューテックスなど、プロセスに結びついた排他制御なら何でも良いと思いますが、往々にしてOS依存があるのが難点かもしれません。
phpだとsyncというクロスプラットフォームな仕組みがあるらしいです。
他に、データベースのロックを使っても良いと思います。

プロセス監視式

今回の場合、これがよいと思います。
exec()で実行すれば、正常にしろ異常にしろ終了まで待ちます。終了したら出力結果やreturn_varを見て異常終了していないか確認します。
つまり、phpのプログラムを直接実行せず、phpのプログラムを実行し、監視するphpのプログラムを作り、それを実行するということです。
http://webkaru.net/php/function-exec-system/
一番素直な実装だと思います。
また、終了コードを記録しておけば、なぜ強制終了させられたかも分かります。
http://www.hiteksoftware.com/knowledge/articles/049.htm
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms681381(v=vs.85).aspx

今の具体的な手順や処理内容を書いてもらえれば、もう少し具体的な事が書けると思います。

他1件のコメントを見る
id:TransFreeBSD

いくつか問題あったので再コメント

即再実行すれば問題ないのなら下記の様になりますかね。

<?php
ini_set("date.timezone", "Asia/Tokyo");
ini_set("log_errors", 1);
ini_set("error_log", "hoge.log");
for ($i = 1; $i <= 10; $i++) {
    error_log("start script");
    $start = time();
    unset($out, $ret);
    exec('c:\php\php.exe -d "date.timezone=Asia/Tokyo" -d "log_errors" -d "error_log=hoge.log" -d "memory_limit=1073741824" c:\php\hoge.php 2>&1', $out, $ret);
    $stop = time();
    error_log("\n    |" . implode("\n    |", $out));
    error_log("stop script with exit code $ret");
    if ($stop - $start < 3) {
        error_log("waiting about 3 * $i sec.");
        sleep(3 * $i); // 3から30秒まで待ってから再起動
    } else {
        $i = 1; // カウンタはリセットする
    }
}
?>

起動終了と、エラー、念のため標準出力、エラー出力の内容をログファイルに残すようにしてみました。
あと、何らかの原因(例えばデータベース接続に失敗とか)で即エラー終了しているといった場合に、延々と再起動を繰り返さないよう、3秒以内に終了が10回続いたら終了する様にしています。

なお、
> ただ、たまに非常に文章量が大きいテキストを受け取ると、プログラムそのものが落ちます。
ってことでメモリ関連をググると下記のような記事が出てきました。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1266281967
http://php.net/manual/ja/ini.core.php#ini.sect.resource-limits
http://d.hatena.ne.jp/hnw/20100801
デフォルト128Mだそうで、越える可能性はありますね。
設定値はphpinfoで確認できます。
これが原因ならば、この値を変えるか、大きなメールは弾くかした方が良いかもしれません。

2015/08/08 20:44:40
id:webtomake

皆様

親身になってご返答頂き、ありがとうございました。

私の質問内容が良くなく、細部までお伝え出来ておりませんでした。

ただ、ご返答頂いた内容はどれも勉強になるものであり、皆様には感謝しております。

一旦、こちらの回答にて閉じさせていただきます。

2015/08/09 21:33:13

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません