この記事の概要
Windowsバッチ(コマンドプロンプト)を使用して、他プロセスとの同期をとるのに、ファイルのタイムスタンプ監視で対応していたが、意図通りに動かない可能性があるようだ。
しかし対策されないまま放置されていた。
何がいけないのか、どうすればいいのか、という話。
前提
1分間隔でフォルダ内ファイルを監視し、配置されたファイルを処理するプロセスAがいる。
処理とは、管理情報を取得した上で、別フォルダにコピー、元ファイルは削除するというもの。
出力先には、既にファイルがあるかもしれないし、無いかもしれない。(初期稼働とか故意にファイルをどけたとか)
但し出力先ファイルの更新日時は確実に更新される。
呼出元(本記事のターゲット)のWindowsバッチから、このプロセスAに対して処理を渡し、完了したことを 確実に 保証した上で後続処理を実行させたい。
この実装のために、こんなコードを書いた。
copy %WORK_FILE% %TARGET_SRC_DIR%\%TARGET_SRC_FILE%
cscript.exe waitWorkComplete.vbs %TARGET_DST_DIR%\%TARGET_DST_FILE%
copy %TARGET_DST_DIR%\%TARGET_DST_FILE% %MORE_WORK_FILE%
cscript.exe moreWork.vbs %MORE_WORK_FILE%
waitWorkComplete.vbs
では、 %TARGET_DST_FILE%
の更新時刻を、 自身の起動時刻 を基準に監視、現在以降であれば処理完了したものとみなす。
単純に起動時刻で比較するのがNGなのはすぐに分かる。そりゃcscript起動して判定コードに到達するのに1秒や2秒かかることはよくあるだろう。
保険として、5秒もマージンとればいいか。。
このプログラム、月に数十回も起動されることないので、これで6年もちました。
6年目に発生し、5秒でもだめなことあるんか、そりゃ実行機の負荷状況によってはありえないとはいえないな。
とりあえずマージンを10秒に広げてみよう。
でもちょっと待て、これ何秒に広げても、ありうるんじゃないの??
さらに保険を加えて、10分待ってもダメだったら打ち切りにしてオーケーにしちゃおう。(後述)
よくわかんないぞ、今まで記録を取れてなかったのがいけない。ちゃんと調べて記録も取るようにしよう。
監視プログラムをvbsで書いたのがいかんのか?Cで書いた小さなプログラムならなんとかなる?
いや、程度の差こそあれ、ゼロにできない以上一緒でしょう。。
結局、どうすりゃよかったの??
落ち着け。
すいません、聡明な一部の読者な方ならすぐ気づいたのでしょうけれども、若輩者な自分はこれ気づくのに6年かかりました。。
(というか、現状を他人に説明する手段がないのでこの記事を書こうとしたときに、脳内が整理された模様)
正解
時刻を基準に判定するなら、確実に信用できる時刻を基準にしなくちゃならない。
でもって、無いなら意図的につくる。
上記の例なら、たとえばこうする。
echo pre-check > %TIMING_FILE%
rem ** 必要に応じてここにsleep入れる(後述) **
copy %WORK_FILE% %TARGET_SRC_DIR%\%TARGET_SRC_FILE%
cscript.exe waitWorkCompleteWith.vbs %TIMING_FILE% %TARGET_DST_DIR%\%TARGET_DST_FILE%
copy %TARGET_DST_DIR%\%TARGET_DST_FILE% %MORE_WORK_FILE%
cscript.exe moreWork.vbs %MORE_WORK_FILE%
waitWorkCompleteWith.vbs
では、(自分の起動日時ではなく)「第1引数ファイルの更新日時」と「第2引数ファイルの更新日時」を比較する。
第1引数ファイルは 確実に 第2引数ファイルよりも前の日時になるので、第2引数ファイルが更新されているなら完了と見なせる。
第2引数ファイルがいつまでも更新されないなら、永久に刺さってしまうが、それはプロセスAに異常事態が生じて、予定されている処理が完了していないということなのだから、絶対に後続は処理してはいけない。(!)
元の実装ではタイムアウト処理を入れてしまっているが、もし発生してしまったら運用で気づけるのか、正直疑問。。。
(プロセスA側にはエラー時にメール通知する仕組みはある、いちおう)
その他
上記例ではファイルシステム上の日時に依存しているので、時刻の精度はファイルシステムおよびプログラム実装の双方で確認が必要。
たとえば万一(※)、FATファイルシステムを使っているのであれば、精度の下限2秒、つまり2秒未満の差異は検出できない。
※今時まずありえないでしょうが。。考えるの大事。
まとめ
一度思い込んでしまうと、いかに抜け出せないかというお話でした。
(そっちかい)