Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cloud Functionsで作るSlack App

mikan3rd
September 29, 2021

Cloud Functionsで作るSlack App

mikan3rd

September 29, 2021
Tweet

More Decks by mikan3rd

Other Decks in Programming

Transcript

  1. Cloud Functionsで作る
    Slackアプリ
    2021/09/29
    mikan3rd

    View Slide

  2. Who is mikan3rd?
    ● Hiroki Ota
    ○ 基本 mikan3rd という名前で活動してます
    ● 1992年生まれ、エンジニア5年目
    ○ JavaScript / TypeScript / Ruby / Python / Go
    ○ TypeScript / React が特に得意
    ● 現在は株式会社ZENKIGEN所属
    ○ 採用向けweb面接「harutaka」
    ○ 録画面接のAI分析「harutaka エントリーファインダー」
    ○ ライブ面接のAIサポート「harutaka インタビューアセスメント」
    ○ エンジニア職も募集中!!
    ● Google CloudのProfessional Cloud Developer認定
    ○ 弊社のインフラは GCPがメインです
    Twitter: @mikan_the_third

    View Slide

  3. 本題
    Cloud Functionsで作る
    Slackアプリ

    View Slide

  4. Q. こんなこと思ったことありませんか?
    ● HTTPリクエストで呼び出せる処理を作りたい!
    ● PubSubで非同期に実行させたい!
    ● cronみたいに定期実行させたい!
    ● (JavaScriptでいう)オブジェクトをそのまま
    DBに保存したい!
    ● CI経由で自動デプロイさせたい!
    ● 1ヶ月あたり無料枠〜数十円におさまる範囲で動かしたい!

    View Slide

  5. それ、         で
    Serverlessでできます!!

    View Slide

  6. Firebaseとは?
    ● mBaaS(mobile Backend as a Servie)
    ● GCPのサービスのうちアプリ開発によく使う機能をまとめて使いやすくしたやつ
    ○ データベースFirestore
    ○ ストレージは Cloud Storage for Firebase
    ○ ユーザー認証は Authentication
    ○ サーバーレスコンピューティングは Cloud Function
    ○ などなど(モバイルアプリ向けの機械学習もある)
    ● インフラや一部バックエンドは
    GCPに任せてサーバーレスで開発できる!
    ○ 上記の機能をフロントから使える

    View Slide

  7. Cloud Functions for Firebaseの良いところ
    ● 関数単位のちょっとした複数の処理をサーバーレスで用意できる
    ○ フレームワーク不要、関数だけでバックエンドサーバーができる
    ○ サーバー(の管理が)レス
    ● 様々なトリガーで関数を起動できる
    ○ HTTPリクエスト
    ○ PubSub
    ○ Cloud Schedulerの自動PubSub連携(定期処理)
    ○ フロント側からSDK経由で直接呼び出し
    ○ Firestore / Storage にデータの変更があった場合
    ○ などなど
    ● firebase-toolsを使用したデプロイが楽
    ○ `firebase deploy` だけ!
    ○ Firestoreのセキュリティルールとかもまとめてデプロイ可能
    ● エミュレーターを使えばローカルでも動作確認可能

    View Slide

  8. Firestoreのいいところ
    ● 何も準備がいらないので楽
    ○ テーブルを追加する必要なし(ドキュメント追加と共に自動で作成される)
    ● ちょっとしたクエリなら使える
    ○ RedisなどのKey-Value型のDBではクエリが書けないが、 Firestoreはドキュメント型なので簡単なク
    エリなら書ける
    ● 少量の使用なら無料枠におさまる
    ○ Cloud SQLなどマネージドDBは最低スペックでも 1ヶ月数千円かかる
    ○ Google Compute EngineにMySQLサーバーを自前で立てることもできるが面倒

    View Slide

  9. 今回作ったやつ

    View Slide

  10. Lively
    ● LivelyはSlack上のコミュニケーションをより便利に楽しくするための機能を複数備えたアプリで
    す!
    ● https://github.com/mikan3rd/lively
    ● 様々なチャンネルから人気の投稿を探して通知します
    ● 週間・月間で人気のあった投稿を振り返ります
    ● アプリのホームタブから簡単に設定ができます
    ● 新しく作成された絵文字やチャンネルをお知らせします
    ● privateチャンネルには関与しないようになっているため安心です

    View Slide

  11. Livelyの構成
    ● TypeScript (Node.js)
    ● Firebase
    ○ Cloud Functions
    ○ Firestore
    ● Slack App
    ○ OAuth Permission
    ○ App Home
    ○ Interactive Components
    ○ Event Subscription

    View Slide

  12. Slack App

    View Slide

  13. Slack App とは?
    ● Slack AppをSlackにメッセージを投げたり、Slackのデータを取得したり、SlackのUIを使って操
    作したりできる
    ● 無料!!

    View Slide

  14. OAuth認証
    ● アプリを作成したworkspace以外でも使え
    るようにするためには、OAuth認証で他の
    workspaceの認証トークンを取得する必要
    がある
    ○ Slack Appを作成したworkspaceのみで使
    用する場合は不要
    ● 使用したいAPIに応じてscopeを付与する必
    要がある
    ○ 今回のアプリでは privateチャンネルに対
    するアクセス権はない
    ● 認証用URLにリダイレクトするendpointと認
    証処理用のendpointを用意

    View Slide

  15. Interactive Component & App Home
    ● Interactive ComponentとはSlackのメッセージにテキス
    トだけでなくボタンやセレクトボックスなどを表示できる
    機能
    ○ 各パーツはJSON形式で決まった構造で組み立てる必要が
    ある
    ○ https://app.slack.com/block-kit-builder でプレビューでき

    ● App HomeをONにするとSlack上でアプリを選択した時
    にHomeタブが表示できるようになる
    ○ ここにもInteractive Componentを表示させることができる
    ○ 今回の場合はここでアプリの設定ができるようにしている
    ● Interactive Componentで選択された結果を受け取る
    endpointが必要

    View Slide

  16. Event Subscription
    ● 特定のイベントが発生した時にリクエストを送ってくれる
    webhook的なやつ
    ○ 先ほどのApp Homeが開かれた時には
    `app_home_opened` というイベントが送られてくるので最新
    のデータを反映した Interactive Componentを送っている
    ○ `channel_created` `emoji_changed` のイベントが送られた
    時にチャンネル作成の通知やスタンプ追加の通知をリアル
    タイムで送るようにしている(簡単)
    ● イベントを受け取るための
    endpointが必要

    View Slide

  17. 実際に触ってみて分かった注意事項

    View Slide

  18. ● 外部へのアクセスなど一部の機能には従量課金プランに切り替えが必要
    ○ と言っても従量課金プランにも無料枠はあるのでそんなに気にすることはない
    ● コールドスタート
    ○ 実行環境はゼロから初期化されるため、関数の実行までその分の時間がかかる
    ● タイムアウト
    ○ 最大9分
    ○ そもそも呼び出し回数、メモリ、実行時間による従量課金なので長く重い処理には向かない
    ● デプロイによる課金
    ○ `firebase deploy` は内部的に Cloud Build を使用しているため Cloud Buildの実行時間が課金対象となる(無料枠あるので
    そう超えないはず)
    ○ 関数は無料枠のない Container Registry に保存されるため、その分のストレージ料金がかかる
    ○ デプロイする度に古い
    Containerが削除されずに溜まっていって課金対象となってしまう
    ● 使えるのは Node.js (JavaScript / TypeScript)だけ
    ○ 普通のCloud FunctionはRuby / Python / Java / PHP / Go でも使えます
    ○ https://firebase.google.com/docs/functions/functions-and-firebase
    ○ `gcloud functions deploy`
    Cloud Functions for Firebaseを使う際の注意

    View Slide

  19. Firestoreを使う際の注意
    ● 読み取り、書き込み、削除のドキュメントの数による従量課金
    ○ 頻繁に上記の処理が発生する場合や大量のデータを扱う場合は不向き
    ○ ページングなどでドキュメントの合計数が欲しい場合もデータの読み取りとして課金される
    ○ コンソール上で上記の処理を行った場合も課金対象
    ● NoSQLなのでRDBでいうリレーションを再現し辛い
    ○ 一応、サブコレクションや参照型など用意されているがクセがある
    ● NoSQLなのでカラムごとに型を制限できない
    ○ KeyとValueのように格納できるが型の制限はできないので想定外の値が入ってもエラーにならない
    ○ またマイグレーションのような概念もない
    ● 複数Keyを使ったクエリを書くには別途
    indexを貼る必要がある

    View Slide

  20. Slackアプリを使う際の注意
    ● レート制限
    ○ 同じAPIを呼べるのは1分間に20回までなどの制限がある
    ○ OAuth認証であればトークンごとに回数が測定される
    ● メッセージを指定して取得する
    APIが存在しない
    ○ そもそもメッセージにサロゲートキーがない(ちなみにメッセージへのリンク取得 APIではチャンネル
    IDをタイムスタンプを指定して取得するのでこれが複合キーっぽい)
    ○ 例えば1年前のとあるメッセージのチャンネル IDとタイムスタンプが特定できていても、 API経由で取
    得するには1年前まで順番に遡るしかない
    ○ メッセージを順番に取得する際にも件数を指定しないといけないので、ヤマカンででかい件数を指定
    して繰り返す処理をしないといけない(レート制限にかからないように)
    ● Event APIには3秒以内にレスポンスを返さないとリトライが走る
    ○ 何か処理を行う時間がないので非同期にしないといけない
    ○ リクエストヘッダーの `x-slack-retry-num` `x-slack-retry-reason` を見ればハンドリング可能

    View Slide

  21. スタンプの多いメッセージを取得・通知するには?
    ● 一定数以上のスタンプがついたメッセージを取得したいが、そのような
    APIはない
    ○ メッセージの一覧を取得する APIで全件取得してスタンプ数でフィルタリングする処理を行っている
    ○ ただしメッセージの一覧はチャンネルごとにしか取得できないので、チャンネル数だけメッセージの全
    件取得を行わなかればいけない
    ○ チャンネル数が多い場合はレート制限に引っかかってしまうため調整している
    ■ Cloud Task
    ○ 上記の処理を毎時実行する定期処理にしている
    ○ また、一度通知したメッセージが重複して通知されないように、通知済みのメッセージのチャンネル ID
    とタイムスタンプは Firestoreに保存してチェックしている
    ● 週間、月間で集計するには?
    ○ 毎時の処理で取得したスタンプの多いメッセージを保存して流用したい
    ○ しかし、メッセージを指定して取得できる APIがないため、上記の処理の取得期間を週間と月間に伸
    ばして実行するチカラ技の処理となってしまっている・・・・

    View Slide

  22. スタンプ数の多いスレッドも通知したい!
    ● メッセージ一覧取得時にスレッドのデータは付与されない
    ● スレッドの一覧はメッセージ指定でしか取得できない
    ● つまり全てのメッセージに対してスレッド一覧取得を行うしかない
    ○ 流石にやめた

    View Slide

  23. 伝えたいこと
    ● ちょっとした用途のバックエンドにはCloud Functions for
    Firebase / Firestoreが便利!安い!
    ● Slackアプリは簡単に作れる(けど制約があるので思い通りにな
    らないことも)
    ● 今回登場してないけどCloud Runも便利!

    View Slide

  24. ご静聴
    ありがとうございました!
    Qiitaでより詳しいコードの解説してます
    https://qiita.com/mikan3rd/items/b3f333314c15c866ab84

    View Slide