Slash Command に対して 3 秒以上かかる処理をする
はじめに
Slash Command は Slack の機能のひとつです。デフォルトでは /remind
や /invite
などがあります。
このようなスラッシュ /
から始まるコマンドは自作することもできます。たとえば、あいさつするコマンド:
/greet 太郎
と打つと- 「こんにちは、太郎。」と返ってくる
を作れます。
Slash Command は、たとえば HTTP をトリガーに起動する Google Cloud Functions を用意して、Slack からのリクエストが来たら適当にレスポンスを返せばいいです。イメージとしては下の図です。
しかし、レスポンスは 3 秒以内にしなければいけません*1。
それでは、Cloud Functions で時間のかかる処理を行うにはどうすればいいのでしょう?
結論
解決方法のひとつは Slack Tutorial - Slash Commands | Cloud Functions Documentation で言及されているように Google Cloud Pub/Sub を使うことです。Slack からのリクエストを受け取る関数とは別にもう一つ関数を用意して、重い処理をそちらに任せます。
この記事では、上の /greet
コマンドを
- Cloud Functions のみで実装
- Cloud Functions + Cloud Pub/Sub を使って実装
します。
たかが /greet
コマンドに (2) の方針を採るのは正直大げさすぎますが、ソースコードの例をシンプルにしたいので /greet
コマンドで説明します。
この記事の内容は、以下の [1], [2], [3] から少しづつ拾い集めただけなので、お急ぎの人はリンク先を追ってください。
- [1] Enabling interactivity with Slash Commands | Slack
- [2] Slack Tutorial - Slash Commands | Cloud Functions Documentation
- [3] Google Cloud Pub/Sub Triggers | Cloud Functions Documentation
Cloud Functions
実装と言っても、ソースコードは以下の 4 行で終わりです。
exports.greet = (req, res) => { const name = req.body.text; res.status(200).send("こんにちは、" + name + "。"); }
マウスをカチカチするパートはだいたい次のような感じです。
- Slack: 適当にワークスペースを作って Slack API: Applications | Slack → [Create New App] → [Slash Commands] → [Create New Command]
- Cloud Functions: 適当にプロジェクトを作って Google Cloud Platform → [Cloud Functions] → [関数を作成] インラインエディタでソースコードを編集する。上記のソースコードをコピペ。
- Slash Command の Request URL を https://example.com → (Function 作成時に決まる URL) に置き換える。(スクショ撮る順番を間違えました。)
ここまでで、Slack で /greet 太郎
と打つとすぐに「こんにちは、太郎。」と Bot が返信するようになりました。
Cloud Functions + Cloud Pub/Sub
図を示します。
「わかった」と返信する部分は簡単です。
新しく知るべきことは主に次の 3 つでしょう。
- Cloud Pub/Sub にデータを送る方法
- Cloud Pub/Sub からデータを受け取る方法
- Slack にあいさつを投稿する方法
(a) と (b) は [3] や Quickstart: Using Client Libraries | Cloud Pub/Sub Documentation を見るとわかります。
(b) のために Cloud Pub/Sub をトリガーとする Cloud Functions を新しく作りましょう。いえ、その前に topic を作る必要があります。それっぽい箇所を Google Cloud Platform のコンソールから探してください。ここでは my-topic
と名前を付けました。
Function を作ります。[トリガー] は Pub/Sub、[トピック] は my-topic とします。
(c) は [3] を見ると、コマンドが実行されたときに Slack から /greet 太郎
と一緒に https://hooks.slack.com/commands/1234/5678
のような URL が送られてくるとわかります。この URL に対して POST リクエストをすればよいです*2。
実装です。
- Publisher
const {PubSub} = require("@google-cloud/pubsub"); exports.publish = (req, res) => { const pubsub = new PubSub(); pubsub.topic("my-topic").publish( Buffer.from(JSON.stringify(req.body))); res.status(200).send("あとであいさつを返します。"); };
- Subscriber
const fetch = require("node-fetch"); exports.subscribe = pubsubMessage => { const data = JSON.parse(Buffer.from(pubsubMessage.data, "base64")); fetch(data.response_url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: "こんにちは、" + data.text + "。" }) }); };
注意点として、@google-cloud/pubsub
などの package を使うために package.json
の dependencies
のところを以下のように編集してください。
動作例です。