人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Windows バッチ処理

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

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

そこで質問です。

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


●質問者: webtomake
●カテゴリ:コンピュータ
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● a-kuma3
●30ポイント

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

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

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


webtomakeさんのコメント
ご返答、ありがとうございます! http://php.net/manual/ja/info.configuration.php#ini.max-execution-time に、「 PHP を コマンドライン から実行する場合のデフォルト設定は 0 です。 」とありますが、当方はコマンドラインから実行しておりますので、このケースは該当しない(=実行時間の制限がかかっていない)事になると思われますが、いかがでしょうか? http://q.hatena.ne.jp/1432284272 の質問の問題は メモリ切れとCPUの利用がマックスに達し、コマンドラインそのものが「落ちた」状態にありました。 そもそもPHPはバッチ処理に向いていない言語であり、メモリ管理も難しいので、しょうがないのかなと考えています。 したがって、監視し、落ちたら再起動させる様な流れをとれればと考えています。

a-kuma3さんのコメント
>> http://php.net/manual/ja/info.configuration.php#ini.max-execution-time に、「 PHP を コマンドライン から実行する場合のデフォルト設定は 0 です。 」とありますが、当方はコマンドラインから実行しておりますので、このケースは該当しない(=実行時間の制限がかかっていない)事になると思われますが、いかがでしょうか? << という可能性はありますが、件の質問では php.ini に max_execution_time に値を設定しているとも、デフォルトのままにしてあるのだとも書かれていないので、第三者には分かりません。 実際に、max_execution_time を長くして試してみたのでしょうか。 >> http://q.hatena.ne.jp/1432284272 の質問の問題は メモリ切れとCPUの利用がマックスに達し、コマンドラインそのものが「落ちた」状態にありました。 << 何をもって、こう判断されたのですか? 少なくとも、コンソールから起動したプロセスに CPU の使用時間でプロセスを強制終了する機能は Windows にはありません。 メモリを食いつぶすようなスクリプトであれば、いずれメモリ取得ができなくて致命的なエラーになる可能性はありますが、その場合には、メモリを食いつぶすような処理を見直すのが本道だと思います。 スクリプトの内容が分からないので、再起動した場合に処理が軽くなっているのだ、ということも第三者には分かりません。 何度も起動して、つじつまが合うような処理(処理対象の残りの数に応じた処理になってる)のであれば、監視とか面倒なことを考えずに、一日に何度か起動すれば良いだけだと思います。 再起動して処理が軽くなるような処理であれば、直前の実行が正しく処理できている場合には、処理対象の件数がゼロなので、すぐに終わるはずですから。 >> そもそもPHPはバッチ処理に向いていない言語であり、メモリ管理も難しいので、しょうがないのかなと考えています。 << 別に php が好きなわけではないので擁護するつもりはありませんが、そういうことではないと思います。 メモリを明示的に割り当てられないのは、Perl や Ruby など LL 系の言語では当たり前です。 その代わり、明示的にメモリを開放するという労苦から解放されるというメリットを享受しています。 php は、良くも悪くも、バッチ処理で求められる要件をよく分からない人にスコープした言語なのだと思います。 プログラム組んでいる人が処理にかかる時間などを気にしない人たち向けなので、言語の機能として、処理時間による打ち切りの機能が設けられている、と。

webtomakeさんのコメント
ご回答、ありがとうございます。 再度検討してみたいと思います。

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

a-kuma3さんのコメント
違う。 popen で起動しているところを exec で起動するようにして、起動するところを無限ループにする、ですね。

2 ● LLマン
●30ポイント

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

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

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


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


3 ● TransFreeBSD
●40ポイント ベストアンサー

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

ウォッチドッグ式

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

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


webtomakeさんのコメント
ご回答、ありがとうございます。 処理内容は下記の通りです: ・stackでメールの受信を待っているプログラムが動いている ・メールを受け取ったら、DBに格納する のような感じです。 したがって、 <?php while(true){ $mail_text = ""; $db->insert($mail_text); } ?> みないなものが動いています。 ただ、たまに非常に文章量が大きいテキストを受け取ると、プログラムそのものが落ちます。 根本的な要因を解決しなければなりませんが、その前に、このプログラムが落ちたことを検知し、バッチファイルを叩き直すプログラムを応急処置的に作りたいと考えています。 ご教示頂いたプロセス監視式はとても良さそうですね。

TransFreeBSDさんのコメント
いくつか問題あったので再コメント 即再実行すれば問題ないのなら下記の様になりますかね。 >|php| <?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で確認できます。 これが原因ならば、この値を変えるか、大きなメールは弾くかした方が良いかもしれません。

webtomakeさんのコメント
皆様 親身になってご返答頂き、ありがとうございました。 私の質問内容が良くなく、細部までお伝え出来ておりませんでした。 ただ、ご返答頂いた内容はどれも勉強になるものであり、皆様には感謝しております。 一旦、こちらの回答にて閉じさせていただきます。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ