エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

Slack botをCloud Runで作る時には気をつけろ

こんにちは、スプラトゥーン3が待ちきれないAI・機械学習チームの丸尾 (@snowhork) です。

みなさん、Slack botは作ってますか? Slack botをつくるときはやはり公式のフレームワーク、Boltがやはり便利ですよね。

みなさん、GCPのCloud Runは使ってますか? ちょっとしたジョブを作って実行するにはやはり便利ですよね。コンテナ実行できるので開発や動作検証もしやすいですし。

f:id:snowhork:20220412175842p:plain
SlackとCloud Runは相性が悪い!?

世の中にこんなに便利なものがあったら、やっぱり組み合わせて使いたくなりますよね。ただ、便利なものには思わぬ副作用があり、見事にハマって1週間苦しんだ体験を残しておこうと思います。この記事でSlack bot開発で苦しむ人が一人でも救われたら幸いです...

何が起きたか?

とにかく実行が遅い。

とんでもなく耐えられないくらい遅い(なお、手元のPCでは速い。)。

今回、Slack botを使ってワークフローを作成し、Bigqueryの権限申請のワークフローを作成しました。申請フォームの内容に応じて、botがgcloudコマンドを実行をする仕組みです。

f:id:snowhork:20220412181719p:plain
今回作成したワークフロー

しかしこのシェルコマンドの実行部分がとにかく遅い。

自分のPCでは1秒で終わるコマンドのはずが、なぜかCloud Run上だと5分以上かかるということが起きました。

結論と原因

結論、Cloud RunのCPUの割り当て「CPU is always allocated」を指定しましょう。デフォルトの「CPU is only allocated during request processing」ではダメです。

f:id:snowhork:20220412174231p:plain
リクエスト処理中にしかCPUが割り当てられない場合

「CPU is only allocated during request processing」では、リクエスト処理中のみCPUの割り当てが行われます。一方で、Slack botは、Slackからのリクエストを受け取ってから、3秒以内に Ack 関数を用いて一旦応答しなければなりません。そのため、Ack 関数を呼んだ時点でリクエスト処理が終了し、CPUの割り当てが行われず、動作が遅かったのです。

謎の現象集

原因は上で述べた通りですが、Cloud Runのその特性を知らないと、謎としか思えなかった現象を最後に供養したいと思います。笑って読んであげてください。

1. ローカルだと全く再現しない

上述の通り、Cloud RunのCPUの割り当ての問題なので、ローカルではもちろん再現しません。ローカルでなぜ再現しないのかと頭を抱えつつ、試行錯誤のたびにCloud Runにデプロイしなければなりませんでした。ちなみに私はこの件で1日50回デプロイしてました。

2. ackより前に呼ぶと速い

デバッグの結果、ackより前にそのコマンドを実行すると、通常の速度で処理されるということがわかりました。 ackを呼ぶと、遅いプロセスが起動されるのかと思い、ackの実装を読み始めました(もちろんただレスポンスを返してるだけなので迷宮入りしました)。

3. 実行すると、前回の内容が実行される

前述の通り、1回目のワークフローを実行した時に、そのコマンド結果が全く返ってきません。結果が返る前に2回目のワークフローを実行すると、先に1回目のコマンドの結果が出力され、2回目のコマンド結果を待つ、という現象が起きました。

これは、2回目のワークフローを開始するとコンテナのリクエストが処理され始めるので、そのコンテナへCPUの割り当てが開始され、止まっていた1回目のコマンドが実行される、というのが現象の説明になります。珍現象過ぎて笑えてきたのですが、Cloud Runの特性だとこのあたりから確信し始めました。

まとめ

Slack botをCloud Run上に乗せるときは、「CPU is always allocated」を指定しましょう!

We are hiring!

エムスリーではBigquery、Cloud Run、GKEなどGCPを活用したプロダクトを盛んに開発しています! エムスリーでクラウドサービスの新しい技術にチャレンジしたい方、下記フォームよりお待ちしております!

jobs.m3.com