AWS Lambda + API Gateway で Slack Bot を動かす

こんにちは、17新卒エンジニアの中嶋です(id:nyamadori)。 イエウール のサーバサイドエンジニアをやっています。

去年の SpeeeKaigi で「Serverless で Speee に Bot 天国を作る」というネタで発表しました。

SpeeeKaigi についてはこちらです。

tech.speee.jp

発表資料

speakerdeck.com

はじめに

無味乾燥とした Web アプリケーションよりも、SlackBot のほうが使っていて愛着が湧くし、いちいち Web ブラウザを開かなくても良いので、楽だと思うことがあります。 そこで、Slack Bot を簡単に作成でき、安全に動かすことができる構成を考えました。 運用をできるだけ楽にしたいので、AWS Lambda + API Gateway を用いた Serverless アーキテクチャを採用し、echo ボットが動くところまで検証しました。

技術構成

構成は以下のとおりです。API Gateway + Lambda Function + Dynamo DB のサーバレスアーキテクチャです。

f:id:nyamadori:20170905153410p:plain

Events API

Events API は、Slack 上のコメントやリアクション等のイベントを、予め設定した Webhook URL に流せる Slack API です。Webhook として、API Gateway の API を指定することで、イベントを Lambda Function に流します。

Events API は、Slack 上のあらゆるイベントをフックできます。取得できるイベントとして、

  • メッセージの投稿 / 編集 / 削除
  • リアクションの追加 / 削除
  • メンバーの Join / Leave

などがあります。フックできるイベント一覧は、https://api.slack.com/events-api#event_types をご覧ください。

Events API を用いる理由は、HTTP 通信でイベントを受け取れることです。Events API に近い仕組みとして、Real Time Messaging API(RTM)や Outgoing Webhooks がありますが、RTM は、イベントの受信に WebSocket 通信を用いるため、API Gateway + Lambda Function でイベントを処理するのには不向きです。Outgoing Webhooks は、メッセージに含まれる文字列をトリガーとしたイベントしか受け取れません。メッセージに付いたリアクションも含めてイベントを受け取りたい場合は、Events API が良いと思います。

Event API の制限

Event API は、一時間あたりの送信可能イベント数が 5000 イベントという制限があり*1、規模の大きい Slack チームで使用する場合は注意が必要です。

直近、弊社では一日あたり約 16000 件のメッセージがやり取りされており、就業時間を 8 時間とすると、一時間あたり 2000 メッセージです。弊社の Slack チームに所属しているメンバーが約 400 人なので、一人 5 件のメッセージを一時間あたりに送っています。メッセージの送信頻度が変わらないとすれば、所属するメンバーが 1000 人以上になると Event API を使った仕組みが使えなくなります。

Event API が使えない大規模な Slack チームの場合は、RTM API を使うことを推奨します。

API Gateway, Lambda Function

API Gateway は、Slack のコメントやリアクション等を HTTP で受け取り、Lambda Functions にイベントを流します。 Lambda Function は、ユーザが作成した Bot プログラムを実行する基盤として使用します。Lambda を使用することで、サーバの環境を壊さないで安全にプログラムを実行できます。 Bot プログラムは JavaScript で記述します。

Lambda Function は、API Gateway からキックされるたび、コマンドに対応するプログラムを Dynamo DB から取得し、プログラムの文字列を Function オブジェクトでラップして実行します。

Lambda を用いる注意点

Lambda Function をデプロイしたばかりの状態や、しばらく起動していなかったときは、Lambda Function がコールドスタートされ、反応時間が遅くなります。コールドスタート状態の場合、Events API へ応答を返すのが遅れるため、Events API からイベント送信のリトライが発生します*2。その結果、同じ Bot プログラムが何度か実行されてしまうことがあります。

それでは困るので、今回は Events API のイベント送信のリトライを無視することにしました。Events API から送られてくるイベントがリトライによるものかは、HTTP ヘッダーに記されているのでそれを元にします。

Yaya との違い

同僚から直前に指摘をもらったのですが、前回の SpeeeKaigi に奇しくも自分のテーマと似たものがありました。

tech.speee.jp

去年の Dueno さんの Yaya との違いは、Bot プログラムがサンドボックス環境で動作するかどうかです。BotFarm は、Lambda Function 上で Bot プログラムが動作するので、Bot プログラムの動作によって、他の Bot プログラムやサーバ環境に影響を与えません。

まとめ

Slack Bot を簡単に作成でき、安全に動かすための仕組みを考えました。

  • Event API を用いることで、API Gateway + Lambda Function を用いて運用の手間のかからない Slack Bot の実行環境を構築できます。
  • Lambda Function で Bot が動くため、Bot が暴走してもサーバ環境に影響を与えません。

成果物

GitHub - nyamadori/serverless-bot: AWS API Gateway + Lambda で実装した Slack Bot 実行環境

今後

まだやりきれていない部分が多く残っているので、

  • プログラムを作成するための管理画面を作る
  • Bot プログラムを簡単に作れるように、プログラムのライブラリを充実させる

*1:https://api.slack.com/events-api#rate_limiting

*2:Slack Event API は、3 秒以内にレスポンスが帰ってこない場合、3 回イベント送信をリトライします。https://api.slack.com/events-api#error_handling