🪄 ホットスポット安定化の魔法 ― 第六の魔法 ― 不死の魔法

不死の魔法 ― 一瞬の呪いで倒れない使い魔

魔法シリーズ第六の魔法。今回は「たまに、いつの間にか倒れている」たちの不安定さです。原因は、メインループに守りの結界がなかったこと。

かかっていた呪い

tgif_daemon.py も dvswitch_bot.py も、長く動かしているとごくたまに倒れていることがありました。再現性は低く、ログにも決定的な痕跡が残らない。気づくのは「あれ、今日は反応しないな」と見に行ったとき。すでに使い魔は消えている。

呪いを追う

倒れるタイミングを探ると、共通して一瞬の OS エラーが絡んでいそうでした。ログファイルが一瞬読めない、stat が FileNotFoundError を投げる(まさにローテーションの瞬間など)、ソケットが一時的にエラーを返す ― そういう「すぐ回復するはずの軽い呪い」です。

ところが当時のメインループは、こうした例外を素通りさせていました。

# 旧き呪文:例外を受け止めていない
while not stop:
    line = f.readline()
    process(line)        # ここで一瞬の I/O エラーが出ると…
    time.sleep(0.1)      # → 例外がループの外まで突き抜けて使い魔が消える

一瞬で回復するはずの呪いでも、受け止めていなければ例外はトップまで伝播し、使い魔ごと消滅します。回復できる呪いで、回復不能な倒れ方をしていたわけです。

呪いの正体

「めったに起きない例外」を放置していたこと。 短い検証では踏まないので気づきにくい。しかし24時間動かす使い魔にとって、「めったに」は「いつか必ず」です。

解呪の魔法

不死の結界 ― メインループ全体を try/except で包み、一瞬の呪いはログに刻んでループを続行するようにしました。暴走を防ぐため、呪いを受けたら少し長めに眠ってから次へ進みます。

# 新しき魔法:ループ全体に結界を張る
while not stop:
    try:
        line = f.readline()
        process(line)
        time.sleep(0.1)
    except FileNotFoundError:
        # ローテーション直後など。次ループで開き直す
        time.sleep(1.0)
    except Exception as e:
        logger.warning(f"main loop で例外を吸収: {e}")
        time.sleep(1.0)      # 暴走防止のクールダウン

これで、回復できる呪いでは倒れなくなりました。tgif_daemon.py v2.4.0 と dvswitch_bot.py v1.48 の両方に張ってあります。

魔導書に記す

24時間動かすものは、「倒れないこと」を機能として設計する。 ロジックの正しさとは別に、「想定外でも消えない外殻」が要ります。ただし結界の張り方には注意が必要で、無条件 except: pass は本当のバグまで覆い隠してしまう。ログに刻む + クールダウンを挟むの塩梅が、運用ではちょうどよかったです。

次がシリーズ最後の魔法。/dev/shm に呪物が残り続ける、後始末の話です。


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

◀ 前へ:第五の魔法 ― /D を見逃さない魔法🪄 魔法シリーズ一覧 | 次へ:第七の魔法(最終話) ― 後始末の魔法

JJ2YYK
  • JJ2YYK

1件のピンバック

コメントする

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