Slack/Teamsを利用して５万人向けの通知システムを作ってみた

この記事は　[リクルート ICT統括室 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/recruit-ict) 3日目の記事です。

# はじめに
はじめまして！ICT統括室 WEBエンジニアリンググループの山川 良太です。
社内向けシステムの開発・ディレクションを担当しています。この記事では Slack/Teamsを利用して社内に通知するシステムを構築した時に得た知見やハマりポイントを共有します。

# この記事で伝えたいこと
- Slack/Teams通知の実装に利用するAPIについて
- Slack/TeamsのAPIで通知を実装する際に考慮した方が良い事

# 背景
毎日たくさん送られてくるメール。みなさんしっかり中身確認していますか？
・自分には関係ないメールばかり届く。「そんなメールきてた？」埋もれて気づかなかった。
・SlackやTeamsなら毎日業務で見ている。けれどメールはほとんど見ていない。
・個別メンション以外の通知は切っている。個人へメンションして欲しい。
必要な人に・いつも使っているツールへ・わかりやすく通知を送りたい。そんな思いからSlack/Teamsでの通知システム開発がはじまりました。

# 構成
今回、構成についてはあまり触れないので簡単な構成図のみ添付します。
- サーバーサイド
    - Ruby on Rails
- データベース
    - Redis
    - RDS
- キューイングライブラリ
    - Sidekiq


![st-ページ2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215065/d04e9764-1d33-4942-9241-45a12cf93a6f.png)

# 通知実装に利用するAPI
### Slack
Slackで個別にメッセージを送信する処理を実装するにはSlack Botを利用します。実装・通知を行う前にSlack Appを作成してください。([参考](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message))
- 通知処理 API
    - chat.postMessage
    - [API Document](https://api.slack.com/methods/chat.postMessage)

### Teams
Teamsで個別にメッセージを送信する処理を実装するにはTeams Botを利用します。

Botアプリを事前に作成し、通知を送信するユーザーに対してインストールする必要があります。
※ Microsoft 365 テナント管理者の場合はテナント内のユーザーに対して自動でインストールする設定を行う事が出来ます。
- アクセストークン取得
    - POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token
    - [API Document](https://learn.microsoft.com/ja-jp/azure/bot-service/rest-api/bot-framework-rest-connector-send-and-receive-messages?view=azure-bot-service-4.0#send-a-non-reply-messag)
- ユーザの会話作成
    - POST /v3/conversations
    - [API Document](https://learn.microsoft.com/ja-jp/azure/bot-service/rest-api/bot-framework-rest-connector-send-and-receive-messages?view=azure-bot-service-4.0#start-a-conversation)
- メッセージを送信する
    - POST /v3/conversations/{conversationId}/activities
    - [API Document](https://learn.microsoft.com/ja-jp/azure/bot-service/rest-api/bot-framework-rest-connector-send-and-receive-messages?view=azure-bot-service-4.0#send-a-non-reply-message)
# その他API制約の確認
実際にAPIを利用する上で、制約などを確認する必要があります。
APIコールのRate Limitに達してしまったり、他の要因によりAPIコールが成功しなかった場合には適切にリトライ・スキップ処理を行う必要があります。

### Slack
Slackについては、[こちらのページ](https://api.slack.com/docs/rate-limits) で詳細が確認できます。
基本的に 1 Slack App あたり1件/秒 しかメッセージを投稿するAPIをコールする事が出来ません。

### Teams
TeamsではAPIコールの前に認証フローを通す必要があり、アクセストークン取得APIを用いてアクセストークンを取得します。

なお、アクセストークンには有効期限が設定されているので、有効期限切れや何らかのエラーなどでアクセストークンが無効になった際には取り直す処理の実装が必要になります。([参考](https://learn.microsoft.com/ja-jp/azure/bot-service/rest-api/bot-framework-rest-connector-authentication?view=azure-bot-service-4.0&tabs=multitenant#step-2-obtain-the-jwt-token-from-the-azure-ad-v2-account-login-service-response))

また、APIの最大リクエスト可能数として1 Teams Bot あたり 50 件/秒 という制約があります。ただし、利用するAPIやそのコール方法によってレートリミットが変わるため[こちらのページ](https://learn.microsoft.com/ja-jp/microsoftteams/platform/bots/how-to/rate-limit)のRate Limit 節を確認しながら実際の開発は行う必要があります。

# リトライ処理について
Slack / Teams のAPI制約とは別にリトライ処理として以下の内容を考慮する必要があります。
- HTTPステータスコード 408(Request Timeout) が返却された
- 何らかの理由でコネクションが確立できなかった
- Exponential Backoff 設定の追加
    - 失敗回数が増えるに連れて再送信するまでの待ち時間を指数関数的に増やす仕組み([参考](https://note.com/artrigger_jp/n/n0795148b062d))
    - AWSを利用する場合はAWS DNSのレートリミット([参考](https://dev.classmethod.jp/articles/amazon-dns-threshold-exceeded-action/))

### Slack
- 特定のHTTPステータスコードでリトライ
    - 429(Too Many Requests)
    - Retry-After ヘッダーが返却された場合はそこに指示されている秒数だけ処理を止める([参考](https://api.slack.com/docs/rate-limits#headers))
### Teams
- 特定のHTTPステータスコードでリトライ
    - 412(Precondition Failed), 429(Too Many Requests), 502(Bad Gateway), 504(Gateway Timeout)
    - 429以外にも指定のステータスコードでリトライする必要がある([参考](https://learn.microsoft.com/ja-jp/microsoftteams/platform/bots/how-to/rate-limit#handle-http-429-responses))

# 通知を送信するにあたって考慮したポイント
- 非同期処理を行いたい
    - Sidekiq(キューイングライブラリ) を使った
- 素早く送りたい
    - Parallel(並列処理を行うライブラリ)を使った
- 送信制限を超えないように通知を送る必要がある
    - Slack送信JobとTeams送信Jobがそれぞれ同時に実行されると送信制限を超える可能性があった
        - それぞれのJobごとに直列で実行するように設定を行った
    - 並列実行しているためコネクションプール数が足りなくなる可能性があった
        - 並列処理で動くスレッド数分を設定に追加した
- Slackの送信速度を上げる必要があった
    - 並列処理のスレッドごとに Slack App を割り当てて高速化した

# まとめ
ここにまとめたことは公式のAPI Documentなどに記載されていることなので、何か目新しいところというのはありません。とはいえ日頃検索で見つけた記事を鵜呑みにして、バージョン違いであったり、間違った情報のせいで思わぬ落とし穴にハマることがあります。

面白くわかりやすく書いてくれている記事は本当にありがたいですが、まずは腰を据えて公式のドキュメントを読むことができる素直なエンジニアでありたいと思っています。

リクルート ICT統括室 Advent Calendar 2023では、リクルートの社内ICTに関する記事を投稿していく予定です。もし興味があれば、ぜひ他の記事もあわせてご参照ください。