🪄 ホットスポット安定化の魔法 ― 第三の魔法 ― inode を見抜く目

使い魔が黙る呪いを解く魔法 ― inode を見抜く目

魔法シリーズ第三の魔法。今回は dvswitch_bot.py(DVSwitch のログを監視して自動で音声応答する使い魔)の話です。一見ちゃんと働いているのに、ある時刻を境に口をきかなくなる、気づきにくい呪いでした。

かかっていた呪い

ログを見ると、朝の 07:20 ごろを最後に音声応答がぱったり止まっていました。使い魔そのものは生きている。倒れてはいない。なのに、その後どれだけ誰がアクセスしても一切応答しない。手で起こし直す(11:52)と、また普通に喋り出す。「倒れる」なら見張りで気づけますが、「生きているのに黙る」呪いは厄介です。

呪いを追う

使い魔は MMDVM_Bridge のログを tail のように追いかけ、カーチャンク(短い送信)を検出したら応答する作りです。止まった時刻を見てピンときました ― 日付が変わるあたりだ、と。

DVSwitch / MMDVM_Bridge はログを日付付きの新ファイルにローテートします。ところが使い魔は起動時に開いたファイルハンドルを握りしめたままでした。

# 旧き呪文:起動時のファイルを握ったまま
f = open(current_path, "r", encoding="utf-8", errors="ignore")
f.seek(0, 2)
while True:
    line = f.readline()   # ローテート後は永遠に "" を返す
    ...

ローテートが起きると書き込みは新ファイルへ移ります。使い魔が握る古いファイルにはもう何も書かれず、readline() は永遠に空文字を返し続ける。使い魔は元気に空ループを回しながら、何も見ていない。これが「生きているのに黙る」呪いの正体でした。

呪いの正体

ファイル名だけ、あるいはハンドルだけを頼りにログを追っていたこと。 とくに MMDVM_Bridge.log のように、名前は同じまま中身が rotate される(truncate / 再作成される)ケースは、名前を見るだけでは見抜けません。

解呪の魔法

inode を見抜く目を授けました。ファイル名が同じでも inode が変われば「別のファイルに化けた」と判断して開き直します。

current_path = _get_latest_log()
f = open(current_path, "r", encoding="utf-8", errors="ignore")
f.seek(0, 2)
current_ino = os.stat(current_path).st_ino       # ★ inode を覚えておく

# メインループ内で定期的に見抜く
latest = _get_latest_log()
if latest:
    new_ino = os.stat(latest).st_ino
    if latest != current_path or new_ino != current_ino:   # 名前 or inode が化けた
        f.close()
        current_path, current_ino = latest, new_ino
        f = open(current_path, "r", encoding="utf-8", errors="ignore")
        f.seek(0, 2)
        logger.info(f"🔄 ログ切替: {os.path.basename(current_path)}")

切替時にログを残し、ちゃんと追従しているか目で見えるようにもしました。これを v1.48 に封じ込め、その後の自分の v1.50 でも継承。2.5時間の連続運転でカーチャンク検出3回、スケジュール送信もすべて時刻通りと、解呪を確認できました。

魔導書に記す

長く使う「ログ追従の使い魔」にとって、ローテーションは「いつか必ず来る」試練。 設計時から織り込むべき正常系です。そして見抜く目はファイル名ではなく inode に宿す。名が変わらず中身だけ化けるパターンを見逃さないための、これが一番確実な術でした。

次の魔法は、その応答処理がメインループを縛っていた話です。


📝 執筆:JJ2TAB(尾張旭 DMR デジピーター 管理人)
🏛 JJ2YYK あいちデジタルコミュニケーションハムクラブ

JJ2YYK
  • JJ2YYK

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です