0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Boltで作ったシンプルなSlack AppをHerokuにデプロイし、URLを公開せずに動かす

0
Posted at

Slack AppをBoltというフレームワークを使って作成し、それをHerokuにホストして、エンドポイントのURLを公開せず動かしてみます。好奇心の実験です。ほとんどSlackのBoltことはじめガイドに書いてあり、基本的にはそれに従って作業していくだけです。例によってDisclaimerですが この記事に書かれている内容はすべて個人の意見・見解・実験・試行の記録であり、Heroku/Slack公式の内容ではありません。

事前準備

  • Herokuアカウントが作成済みで、かつEcoサブスクリプションを利用中であること(要するにHeroku上でアプリを動かす準備が整っていること)
  • Slack Workspaceを作成済であること(無料プランでもOKですが無料プランの場合Slack Appは10個までという制限があるので既に10個Slack Appをインストール済の場合は削除必要です)
  • ローカル端末にheroku CLIがインストール済であること

Slack側の準備

Slack Appの作成

https://api.slack.com/apps に移動して[Create New App]をクリック
image.png

[From Scratch]を選択
image.png

アプリ名とアプリをインストールする先のワークスペースを選択
image.png

左側のメニューから OAuth&Permissions を選択し、Bot Token Scopesまでスクロール、chat.write を追加
image.png

左側のメニューから Socket Modeを選択し、Enable Socket ModeのトグルをON
image.png

App-Level Tokenの発行が求められるので適当に名前をつけて[Generate] (ここでは"test"と入力)
image.png

App-Level Tokenが発行されるのでコピー ... (1)
image.png

ここでコピーをミスっても、Basic InformationページのApp-Level Tokensセクションで見れます
image.png

左側のメニューからEvent Subscriptionsを選択し、Enable Event SubscriptionのトグルをON
image.png

Slack Boltことはじめガイドに従い、message.channelsmessage.groupsmessage.immessage.mpimを追加
image.png

画面下部の[Save Changes]ボタンをクリック
image.png

※既にアプリをワークスペースにインストール済だと、ここで再インストールを促されます。
image.png

左側のメニューからInstall Appを選択し、[Install to (ワークスペース名)]をクリック
image.png

[Allow]をクリック(※この画像はEvent Subscriptionで追加したパーミッションなどが欠けている状態のスクリーンショットです。Event Subscriptionでパーミッション追加していると右側のPermissionsの項がもう少し増えます)
image.png

OAuth Tokenが表示されるのでコピー ... (2)
image.png

Basic Informationのページに移動して Signing Secretを表示・コピー ... (3)
image.png

(1)(2)(3)は後程使うのでメモっておきます。

Slack Channelの準備

Slackのデスクトップアプリを開いて、適当にChannelを作成。publicでもprivateでもいいです。
image.png

Channelページの右上にあるワークスペースのアイコンをクリック
image.png

[Integrations]タブにある[Add an App]をクリック
image.png

先ほど作成したSlack App名を入力してフィルタリング・[Add]をクリック
image.png

これでSlack側の準備が整いました。

Herokuアプリの作成

https://dashboard.heroku.com/apps から[New]をクリック
image.png

適当に名前をつけてHerokuアプリを作成
image.png

[Settings] タブに移動し、Buildpacksの項でNode.jsのビルドパックを追加
image.png

Config Varsの項で以下の環境変数を設定

  • SLACK_SIGNING_SECRET = 上記の(3)
  • SLACK_BOT_TOKEN = 上記の(2)
  • SLACK_APP_TOKEN = 上記の(1)

ちなみにこの先動かすSlack AppはTypescriptのコードですが、Node.js 22以降はnodeコマンドによる.tsファイルのネイティブ実行が可能なので、その前提でtscによるトランスパイルを実施しません。通常tscdevDependenciesに入り、かつHerokuはデフォルトでビルド中にdevDependenciesをPruningするので、ちゃんとやるなら(?)NPM_CONFIG_PRODUCTION=falseなどの環境変数の追加が別途必要です。(これは使用するパッケージマネージャーによって違います。詳しくはこちらをご確認ください。)私は面倒くさいのでやってないだけです…

[Deploy] タブに移動し、Slack Boltで開発したSlack Appを選択。とりあえずここでは私のサンプルコードを使います。
image.png

私のサンプルコードは、基本的にBoltことはじめガイドの実装をそのまま使ってるだけです。これはjavascriptで書かれているので、Typescriptで書き直してみようと思ってやってみたんですが、この範囲だと残念ながらあまり型の恩恵を得られないので、おとなしくjavascriptで書いた方が幾分かマシかもしれません。

[Deploy Branch]をクリック
image.png

ローカルで以下のコマンドを実行

$ heroku ps:scale web=0 -a (your heroku app name)
$ heroku ps:scale worker=1 -a (your heroku app name)

Herokuは最初のアプリの起動時、デフォルトでwebプロセスのみを立ち上げます。が、今回はwebプロセスを使わずworkerプロセスだけを使います。今回のHerokuアプリはPORT環境変数を使ってアプリのプロセスを公開しておらず、webプロセスの起動にそもそも失敗します。なのでwebは0にスケールして(=動かさず)、workerだけを動かす形に変えます。

うまく動いてればHerokuアプリのログに以下のようなメッセージが出力されているはず

Apr 09 22:40:33 (your heroku app name) app/worker.1 [INFO] bolt-app ⚡️ Bolt app is running!

ready to talk with Slack App!

Slack AppをインストールしたChannel上でhello @(slack app)の形でメンションしてみます。
image.png

と、いうことで、Slack Appが反応してくれました。

Slack App側で以下のようなログ仕込んでおけばHerokuアプリのログとしても確認できます。

app.message('hello' , async({message, say})=>{
    console.log('debug:' + JSON.stringify(message)); // ←これ
    if ('user' in message) {
      await say(`Hey there <@${message.user||''}>!`);
    }
});
Apr 09 22:17:24 hogehoge app/worker.1  debug:{"type":"message","user":"xxx",...,"channel_type":"group"}

ポイントと注意点

このアーキテクチャのポイントは、Herokuアプリ側をworkerプロセスにしていることで、つまりHerokuアプリのURLを使用しないでSlackと通信していることだと思っています。Boltことはじめガイドにもあるように、Socketモードだと、起動時にSlackとWebsocketで接続を確立し、以後はそれを使ってやり取りするため、クライアント側のエンドポイントを公開する必要がありません。クライアント側の視点で言えば、起動時にSlackとWebsocketで接続する際のOutboundの部分の通信さえできれば、他のInboundは閉じててもいいわけで(Outboundがステートフルである前提にはなりますが)、だとするとHeroku側はworkerプロセスみたいにバックグラウンドのバッチジョブみたいにして待ち構えるようにすればいけるんじゃね?と思ってやってみたら実際できてィヤッホォウ!!(?)ってのを確認するための記録記事でした。同じ考え方で、Herokuに限らず他のランタイムでも同じようなことはできそうです。(Cloudflare Workersとか、Edge Comuputingのランタイムだと若干話は違ってきそう)

一つ注意なのが、Slack Appを2つ以上のクライアントから起動すると、後から起動したほうで接続が上書きされるところです。HerokuでSlack Appを起動した後、ローカルで同じSlack Appを起動すると、つながるのはローカル側になり、最初に起動したHeroku側のほうは切断されるみたいです。「みたい」というのは、実際ログ等にも特にメッセージが出力されず、反応するのが後から起動したほうだけになったので、事象からそう切り分けしてるだけですが。サイレントに接続が切られてしまうと運用上は厄介かもしれませんね。あるSlack Appが起動中に別のクライアントから同じSlack AppにSocketModeで接続を試みた場合は接続を拒否、とかできたりするのかな??

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?