前回(第40回)は「19年分を掘って天井は95.6%でした」という、届かなかった記録でした。
今回は数字の話ではありません。運用の話です。
自動投票が4日間、1点も馬券を買っていませんでした。そして誰も気づきませんでした。
起きたこと
地方競馬の自動投票を回しています。毎朝9時にタスクが起動し、条件に合う馬が見つかったら、締切の少し前に自動で投票する。そういう仕組みです。
8月15日、16日、18日、21日。この4日間、投票が1点も出ていませんでした。
候補は挙がっていました。8月21日は8レースが候補に残り、判定の予定時刻まで表に書き出されていました。それが1件も実行されなかった。
そして、この4日間ずっと、監視は「異常なし」を表示していました。
毎回、発覚のきっかけは同じでした。人間が「地方はどうなりましたか」と聞いたときです。
監視が正常と言っていた理由
調べてみると、拍子抜けするほど単純でした。
監視スクリプトは3つのプロセスを見ていました。中央競馬の観測、地方競馬の観測、そしてもう1本の執行プロセス。この3本については、ちゃんと動いていました。
投票を出しているプロセスだけが、リストに入っていませんでした。
監視していたもの 観測プロセス(データを集めるだけ)
観測プロセス(データを集めるだけ)
執行プロセス(別系統)
監視していないもの ← 実際に馬券を買っているプロセス
いちばん金が動くところだけが、誰にも見られていなかった。
理由は歴史的なもので、監視を作った時期には投票プロセスがまだ存在しなかった。後から足したときに、監視への登録を忘れた。それだけです。
「異常なし」は嘘ではありませんでした。見ている範囲では本当に異常がなかった。ただ、見る範囲が間違っていました。
これは監視を持っている人なら誰でも刺さる話だと思います。監視の価値は「何を見ているか」ではなく「何を見ていないか」で決まります。
では、なぜプロセスは死んだのか
ここからが本題です。ログを見ると、こうなっていました。
[12:03:00] 待機中 次のレースまで 282分
(ここで途切れる)
==============================================================================
[END] 終了コード -1
例外もエラーもありません。 待機中の心拍が途切れて、いきなり終了コード -1。
Pythonの例外なら、トレースバックが残ります。何も残っていないということは、プロセスの外から殺されたということです。
そこでWindowsのシステムイベントログを見ました。
2026/08/18 12:06:59 Starting unmount for device ...
2026/08/18 12:07:07 Mounting successfully done.
クラウドストレージのクライアントが、ドライブを一瞬アンマウントして、8秒後に再マウントしていました。
そして、投票スクリプトはそのドライブの上に置いてあります。
実行中のプロセスの足元から、ファイルシステムが消えた。それだけの話でした。
対照実験になっていた
面白いのは、これが偶然きれいな対照実験になっていたことです。
| 日 | ドライブの再マウント | プロセスの結末 |
|---|---|---|
| 8/18 | 12:06:59(稼働中) | 強制終了・全滅 |
| 8/21 | 12:07:13(稼働中) | 強制終了・全滅 |
| 8/19 | 0:07:05(起動前) | 🟢 20:48まで完走 |
| 8/20 | 0:07:10(起動前) | 🟢 20:13まで完走 |
プロセスが動いている時間帯に再マウントが起きた日は2日だけ。そしてその2日だけが死んでいます。
n=2です。統計的にどうこう言える数ではありません。でも機構が明確で、対照日が全部生きているなら、これは十分に強い証拠だと思っています。
「相関があるから因果だ」ではなく、「こういう順序で起きるはずだ」という筋書きを先に立てて、それが観測と一致するか見る。データ分析でも運用でも、やることは同じです。
「再起動する設定」は最初から効いていなかった
さらに調べて、もうひとつ出てきました。
このタスクには「失敗したら3回まで、5分おきに再起動する」という設定が入っていました。入れた記憶もあります。それなのに、再起動していない。
理由はWindowsの仕様でした。
タスクスケジューラの「タスクが失敗した場合の再起動」は、プログラムの終了コードでは発火しません。
プロセスの起動自体に失敗したときだけです。
つまり、プログラムが exit -1 で死んでも、タスクスケジューラから見れば「タスクは正常に完了した」。再起動の対象になりません。
設定は入っていた。安心もしていた。でも一度も動く条件を満たしていなかった。
これも監視の話と同じ形をしています。「入れてある」と「効いている」は別のことです。そして、効いているかどうかは、実際に壊してみないと分かりません。
直したこと
投票プロセスを監視の対象に入れました。判定のロジックは既存の点検スクリプトを別プロセスで呼ぶだけにしています。同じ判定を2箇所に書くと、必ず片方が古くなるからです。
そのうえで、警報を2段階に分けました。
・全滅 1件も判定できていない = 投票が1点も出ていない
🟡 一部欠け 一部のレースでオッズが取れなかった
理由があります。一部欠けはほぼ毎日出ます。地方競馬のオッズ取得は不安定で、15レース中4レース落ちるような日が普通にあります。これを全滅と同じ音で鳴らすと、本物の全滅が日常のノイズに埋もれます。
まさにそれが起きていたわけです。
そして、必ず壊れた日に当てる
いちばん大事なのはここだと思っています。
新しい監視を書いたら、既知の障害日に当てて、実際に鳴ることを確かめます。
8/21 → ・全滅 (実際に全滅した日)
8/18 → ・全滅 (実際に全滅した日)
8/19 → 🟡 一部欠け (15レース中4レース落ちた日)
8/20 → 🟡 一部欠け (9レース中2レース落ちた日)
8/17 → 異常なし (3候補3判定2投票の、実際に健全な日)
6日分に当てて、鳴るべき日に鳴り、鳴るべきでない日に黙ることを確認しました。
「異常なし」しか出したことのない監視は、監視ではなく飾りです。障害の最中に「異常なし」と言う計器は、無いより悪い。今回それを実演してしまいました。
まだ直っていないこと
正直に書いておきます。
検知はできるようになりましたが、プロセスが死ぬこと自体は止まっていません。
根本的に直すなら、スクリプトをクラウド同期フォルダの外に置いて実行する必要があります。それは実行環境の構成変更なので、今日の作業には入れていません。
このまま何もしなければ、月に2〜4日、投票がゼロの日が出続けます。
今回の教訓
数字は1つも進みませんでした。回収率も的中率も動いていません。それでも、これは書いておく価値があると思っています。
- 監視の価値は「何を見ていないか」で決まる。 見ている範囲の「異常なし」は、何も保証しない
- いちばん金が動くところから監視する。 うちは逆になっていた
- 設定を入れただけでは効いていない。 壊してみるまで分からない
- 警報は段階を分ける。 毎日鳴るものと同じ音にすると、本物が埋もれる
- 新しい監視は、既知の障害日に必ず当てる。 鳴ることを確かめてから運用に載せる
- 人間が「どうなってる?」と聞いて初めて発覚する仕組みは、監視ではない
4日分の記録は取り返せません。それが今回のコストです。
次回は数字の話に戻ります。券種を複勝から単勝に変えたらどうなるか、19年分で測っています。
静かだったのは平和だからじゃない。誰もいなかったからだ。


