概要
Daemon WebSocket API は、Daemon クライアントがリアルタイムでメッセージを受信・処理するための永続的な双方向接続を提供します。クライアントがポーリングする REST API とは異なり、WebSocket 接続により Shannon は受信メッセージ(Slack、LINE、またはシステムイベントから)を接続済みの Daemon に直接プッシュできます。 このプロトコルの中核は Claim ベースのメッセージディスパッチモデルです。Shannon は対象となるすべての接続にメッセージをブロードキャストし、Daemon が排他的処理権を競い合ってから応答します。エンドポイント
認証
認証は WebSocket アップグレードの前に、REST Endpoint と同じミドルウェアで実行されます。接続ライフサイクル
1
HTTP アップグレード
クライアントが認証 ヘッダー 付きで
GET /v1/ws/messages を送信します。サーバーは資格情報を検証してからアップグレードを行います。2
WebSocket 確立
サーバーが WebSocket にアップグレードします(gorilla/websocket、4KB 読み書きバッファ、CheckOrigin はすべてのオリジンを許可)。
3
接続確認
サーバーが
connected メッセージを送信して、接続の準備完了を確認します。4
双方向メッセージング
双方が JSON メッセージを交換します。サーバーが受信メッセージをディスパッチし、クライアントが Claim、処理、応答を行います。
5
キープアライブ
サーバーは 20 秒ごとに WebSocket Ping を送信します。クライアントは 60 秒以内に Pong で応答する必要があり、応答がない場合は接続が切断されます。
接続パラメータ
メッセージエンベロープ
すべてのメッセージ(双方向)は統一されたエンベロープ形式に従います:サーバーからクライアントへのメッセージ
connected
WebSocket 接続の確立直後に一度だけ送信されます。
message
処理のためにディスパッチされたインバウンドメッセージ。これは主要なメッセージタイプで、Channel Webhook(Slack、LINE)またはシステムイベントからのメッセージを伝達します。
MessagePayload フィールド
system
Shannon からのシステムレベル通知。
claim_ack
クライアントの claim リクエストへの応答。Claim が許可されたかどうかを示します。
クライアントからサーバーへのメッセージ
claim
メッセージの排他的処理権を要求します。同一メッセージを Claim できるのは 1 つのクライアントのみです。
progress
Claim 済みメッセージの処理中にハートビート/進捗更新を送信します。Claim のリースが延長され、タイムアウトを防ぎます。
reply
Claim 済みメッセージの処理結果を送信します。Shannon はこれを送信元 Channel(Slack、LINE など)にルーティングします。
ReplyPayload フィールド
disconnect
接続をグレースフルに閉じます。
Claim フロー
Claim フローは分散メッセージ処理の中核プロトコルです。複数の Daemon が接続されていても、各メッセージが 1 つの Daemon のみで処理されることを保証します。1
メッセージディスパッチ
メッセージが到着すると(Channel Webhook またはシステム経由)、Gateway は
tenant:user でインデックスされたすべての対象 WebSocket 接続にメッセージをディスパッチします。2
Claim 競争
メッセージを処理したい各 Daemon が
message_id を含む claim リクエストを送信します。3
アトミック解決
Gateway が Redis でアトミックに Claim を実行します(
SETNX)。最初のクライアントが獲得し、他のクライアントは {"granted": false} を受信します。4
メッセージ処理
獲得した Daemon がメッセージを処理します。オプションで
progress メッセージを送信して Claim リースを延長し、処理状況を報告できます。5
応答送信
Daemon が処理結果を含む
reply を送信します。Shannon はこれを送信元 Channel にルーティングします。Claim メタデータ
メッセージが Claim されると、Gateway は Redis にメタデータを保存します(TTL 60 秒):保留中メッセージのメタデータの TTL は 90 秒です。Claim 済みメッセージが 60 秒以内に応答されない場合、Claim は期限切れとなり、メッセージは再ディスパッチの対象となります。
Hub アーキテクチャ
WebSocket Hub はすべてのアクティブな接続を管理し、以下のルーティング戦略を採用しています:- Tenant-User インデックス — 接続は
"tenant:user"キーでインデックスされ、ターゲットディスパッチを実現 - スレッドスティッキールーティング — 同一スレッド(
"channel_type:thread_id")からのメッセージは可能な限り同じ接続にルーティング - Redis バックドの Claim — 分散 Claim 解決により、複数の Gateway インスタンス間の一貫性を確保
応答ルーティング
Gateway が Daemon からreply を受信すると、Claim メタデータに基づいて応答をルーティングします:
- Workflow 応答 — Claim メタデータに
workflow_idが存在する場合、Gateway は関連する Temporal Workflow に Signal で通知します - Channel 応答 — それ以外の場合、応答は送信元 Channel にルーティングされます(Slack メッセージ、LINE Push メッセージなど)
エラーハンドリング
次のステップ
Channels API
Slack と LINE の Channel 統合を管理
ストリーミング
Server-Sent Events によるタスクストリーミング