← 一覧に戻る
Telegram プラグイン 永続メッセージキュー 実装レポート
2026年5月1日 14:45 更新
MD から自動変換されたページです。内容について質問があれば右下の ? ボタンからどうぞ。
- 作成日: 2026-04-09 23:56 JST
- 担当: Kurisu (j-20260409-011)
- 元タスク: 秘書セッション busy 時の連投メッセージ脱落の根本解決
何が起きていたか
健人が Telegram で連投したメッセージのうち、中間が静かに消える問題があった。
- プラグイン(Telegram を Claude Code に橋渡しする小さなプログラム) は 4 通とも物理受信完了していた
- 秘書セッションに届いたのは最後の 1 通だけ
- 残り 3 通は「プラグイン → Claude Code 本体」の転送経路で消えた
- 原因は Claude Code 本体の channel notification ハンドラが、セッションが忙しい時に古い通知を新しい通知で上書き (coalesce) している疑い濃厚
- 詳細は先行調査 (j-20260408-038) のレポート参照
何を直したか
プラグインに永続メッセージキューを追加し、以下の動作に変えた。
- メッセージを受信したら、まず
~/.claude/channels/telegram/queue.jsonl に 1 行書き込む (enqueue 行)
- Claude Code 本体に通知を送る (今までと同じ)
- 送信成功したら queue に delivered 行を追加で append
- セッション再起動時、delivered 行が付いていない enqueue 行を古い順に再送する
- 全部送り終えたら queue ファイルを compact (完了済みを削除して書き直し)
これで Claude Code 本体の coalesce が起きても、再起動 = busy 解除のタイミングで pending を押し流して全メッセージを秘書に届ける。
実装内容
追加ファイル
external_plugins/telegram/queue.ts (149 行)
appendEnqueue(entry) / appendDelivered(id) / loadPending() / compact() の 4 関数
- JSONL append-only、fs モジュール直接、依存追加なし
external_plugins/telegram/queue.test.ts (156 行、12 ケース)
- insertion 順保持、delivered 後の除外、compact 動作、壊れた行の skip、冪等性
server.ts の変更
- import に
./queue を追加
- handleInbound の末尾
mcp.notification 送信を appendEnqueue → await deliverAndMark に置き換え
deliverAndMark ヘルパーを抽出 (送信成功時に appendDelivered)
replayPendingQueue を起動時 (bot.start の直前) に実行
重要な副次効果
mcp.notification() を await する ように変更した (元は fire-and-forget)
- これは先行調査の「案1」に相当。stdio transport 送信が sequential に保証される
どう確認したか
単体テスト
$ bun test queue.test.ts
12 pass
0 fail
21 expect() calls
Ran 12 tests across 1 files. [123.00ms]
カバーしたケース:
- 複数 enqueue が書いた順で取れる
- queue ファイルが無い時は空配列
- payload の round-trip (content, meta が壊れない)
- delivered マークで loadPending から消える
- 全件 delivered で pending が空
- delivered 行が先に来ても冪等
- compact 後に delivered 済みが消える
- 空 queue の compact は no-op
- 全件 delivered で compact すると空ファイル
- 壊れた JSON 行は警告ログ付きで skip
- queue ファイル消失時は空配列
- 同一 id の二重 enqueue も pending 1 件
構文チェック
$ bun build ./server.ts --target=bun --outdir=/tmp/tg-buildcheck
./server.js 1066.67 KB
[27ms] bundle 244 modules
バンドル成功 = 型と import パスに問題なし。
未解決の残課題
- 実機確認は秘書セッション再起動待ち: 今動いている Telegram プロセス (PID 83490) は旧 server.ts を読み込んだまま。新コードを反映するには秘書セッション (またはプラグインプロセス) の再起動が必要。再起動は破壊的なので健人の判断に委ねる
- 真の ack (秘書が読んだ証拠) は未実装: 現状は「notification 送信 API 呼び出しが throw しなかった = delivered」扱い。Claude Code 本体が coalesce するなら送信成功でも実は届いていない。これは起動時 replay で補う設計
- 起動直後に秘書が busy なパターンの検証: 再起動直後は秘書が idle 状態であることを暗黙の前提にしている
- コールバッククエリ (inline button) はキュー化していない: 頻度低くボタン操作なので連投しない前提 (YAGNI)
- upstream issue 報告: Anthropic 側への改善提案はまだ
反映手順 (秘書セッション再起動後に読むこと)
- 秘書セッションを
/exit で終了するか、Telegram プラグインプロセス (PID ps aux | grep server.ts で確認) を kill する
- プラグインが再起動すると新 server.ts と queue.ts が読み込まれる
- 初回起動時は queue.jsonl が空なので
replayPendingQueue は即 return (ログに何も出ない)
- メッセージを送って
~/.claude/channels/telegram/queue.jsonl に enqueue と delivered 行が追加されるか確認
- 連投テスト: 秘書を Bash で busy にしつつ 4 連投 → 最初は一部しか届かなくても、次回起動時に pending が replay される
関連ファイル
- 設計書:
~/plans/telegram-persistent-queue.md
- パッチ控え:
~/.claude/patches/telegram-plugin-persistent-queue.patch
- queue.ts 控え:
~/.claude/patches/telegram-plugin-queue.ts
- queue.test.ts 控え:
~/.claude/patches/telegram-plugin-queue.test.ts
- 調査レポート:
~/Library/Mobile Documents/iCloud~md~obsidian/Documents/notes/Second-Brain/2026-04-09_Telegram連投脱落問題_調査.md