mcpField
R
rails-webhooks

rails-webhooks

github.com/marckohlbrugge開発73051 回インストール20 週間前に更新
リポジトリ

rails-webhooks について

rails-webhooksは、Rails開発者向けにWebhookの送受信、セキュリティ、運用の設計指針をまとめたガイドです。永続化された配信記録、障害の分類、サーキットブレーカーを重視します。

主な機能

  1. 01outboxパターンによる配信の永続化
  2. 02宛先障害とコード例外の区別
  3. 03失敗追跡と自動停止
  4. 04SSRF対策と署名検証
  5. 05宛先アダプターとテナント分離
  6. 06配信記録の整理と監視

活用シーン

  1. 01再開可能なアウトバウンドWebhookの設計
  2. 02監査記録を使った配信障害の調査
  3. 03SSRFからWebhook宛先を保護
  4. 04サーキットブレーカー付き管理画面の構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/marckohlbrugge/37signals-skills --skill rails-webhooks

インストール後、Claude Code で/rails-webhooksを入力して読み込まれたか確認します。

詳細

Rails Webhooks

送信/受信 Webhook のアーキテクチャと信頼性に使用します。Fizzy のイベント駆動型 Webhook パイプラインを参考にしており、対比として Campfire のよりシンプルなボット Webhook を取り上げています。

配信モデル(outbox パターン)

  • ドメインイベントはディスパッチジョブを 1 つキューに追加します。ディスパッチジョブはファンアウトし、Webhook ごとに、状態を表す enum(pending in_progress completed errored — index_by(&:itself) による文字列ベース)を持つ永続化済みの Delivery 行を 1 つ作成します。
  • 各配信行は after_create_commit :deliver_later によって、それぞれの送信を自動でキューに追加します。先に永続化し、その後に配信するため、クラッシュや再試行が発生しても状態が保持されます。
  • ActiveJob::Continuable によって、ファンアウトをクラッシュセーフにします。一致する Webhook を対象にカーソルを進める(find_each(start: step.cursor) + step.advance!)ことで、バッチの途中でクラッシュしても最初からではなく、中断した位置から再開できます。
  • 監査やデバッグのため、リクエストのメタデータ(ヘッダー、ペイロード)とレスポンス(ステータス、本文)を配信行に記録します。実行中のバイト数をカウントし、保存・ストリーミングするレスポンス本文は約 100KB に制限します。
  • 専用の webhooks キューを使用し、応答の遅い宛先が他の処理を妨げないようにします。

失敗の分類(重要な違い)

  • 宛先側で発生する想定内の失敗(タイムアウト、TLS、DNS、接続拒否、HTTP 4xx/5xx):例外を捕捉し、記号形式のエラー(response: { error: :connection_timeout })を付けて配信を completed にします。配信処理は実行され、宛先側で失敗したということです。ジョブを再試行しないでください。
  • 想定外の例外(こちらのバグ):errored! にしてから、ActiveJob の再試行が行われるように例外を再送出します。
  • この区別により、再試行の挙動、ダッシュボード、滞留状況の追跡を正確に保てます。

滞留を防ぐサーキットブレーカー

  • Webhook ごとに連続失敗数と first_failure_at を追跡し、最低期間内に N 回失敗したら自動で無効化します(Fizzy の場合:1 時間以上の期間に 10 回失敗)。
  • 成功時にカウンターをリセットします。
  • 手動で再有効化するエンドポイント(resource :activation)とともに、UI に非アクティブ状態を表示します。

セキュリティの基本対策

  • Webhook URL は信頼できない入力として扱い、SSRF に対する包括的な保護を適用します(IP を解決・検証し、プライベートレンジをブロックし、IP を固定し、リダイレクトのたびに再検証します。rails-security-multitenancy を参照)。
  • 作成時だけでなく、送信時にも宛先を再検証します。
  • 宛先 URL は作成後に変更できません。更新で許可するのは名前とサブスクリプションのみです。宛先を変更する場合は、新しい Webhook(および新しいシークレット)が必要です。
  • ペイロードに署名します。HMAC 署名ヘッダーとタイムスタンプヘッダーを使用します。
  • モデル層で購読可能なイベントをホワイトリスト化します:normalizes :subscribed_actions, with: ->(v) { Array.wrap(v).map(&:to_s).uniq & PERMITTED_ACTIONS }。
  • Webhook 管理エンドポイントには管理者レベルの認証を必須にします。

インテグレーションアダプター

  • 1 つの配信パイプラインで複数の宛先タイプに対応できます。URL パターン(for_slack?、for_campfire?)で判別し、宛先ごとにコンテンツタイプ、ペイロード形式(JSON/フォーム/HTML)、レンダリングテンプレートを切り替えます。インテグレーションごとに配信コードを分岐させないでください。
  • ペイロード内の URL は、テナントに適した script_name を使ってレンダリングし、リンクが正しく機能するようにします。

受信 Webhook

  • 最初に署名を検証し(construct_event 形式)、その後、ペイロードの内容や順序を信頼せず、プロバイダーの API から正式な状態を再取得します。
  • チャットボット形式のコールバックでは、コンテンツタイプに応じて実行できる応答を制限します(text/plain/text/html のみを返信にします)。また、ループを防ぐため、ボット自身のメッセージによってボットが起動しないようにします。

テナントの安全性

  • Webhook レコードと配信クエリをテナントの範囲内に限定します。
  • イベントのファンアウトによってテナント間でデータが漏えいしないようにします。

運用上の衛生管理

  • 保持ポリシーに従って古い配信レコードを定期的に削除します(例:4 時間ごとに、古いレコードを対象とするスコープに対して delete_all を実行)。
  • Webhook 管理 UI に配信状況と履歴を表示します。
  • 成功率、再試行、レイテンシーに関する有用なログとメトリクスを出力します。

危険信号

  • 永続化された監査証跡のない、送信したら終わりの配信。
  • 宛先の障害をコードエラーと同じ方法で再試行すること。
  • 変更可能な Webhook の宛先 URL。
  • サーキットブレーカーがなく、停止したエンドポイントに延々とリクエストを送り続けること。
  • 宛先からのレスポンスを上限なく読み込むこと。
  • 配信の作成/検索でテナントのスコープが設定されていないこと。
  • 大量のイベントに対するバックプレッシャーやキューの分離がないこと。

コメント