🪄 ホットスポット安定化の魔法 ― 第六の魔法 ― 不死の魔法
不死の魔法 ― 一瞬の呪いで倒れない使い魔

魔法シリーズ第六の魔法。今回は「たまに、いつの間にか倒れている」たちの不安定さです。原因は、メインループに守りの結界がなかったこと。
かかっていた呪い
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 を見逃さない魔法 | 🪄 魔法シリーズ一覧 | 次へ:第七の魔法(最終話) ― 後始末の魔法 ▶
1件のピンバック
🪄 ホットスポット安定化の魔法 ― 第七の魔法(最終話) ― 後始末の魔法 | JJ2YYK 尾張旭DMRデジピーター