はじめに

生成AI系のSlackbotを作成してCloud Runへデプロイしたところ、動作が不安定で連投してしまう問題が発生したのでその対処法を備忘録として残します。
ちなみにPythonでSlack Boltを使用してアプリケーションの開発をしています。

やったこと

まず、コード上でやったことを説明していきます。

1. Lazyリスナーの設定をする

Slack Appには3秒ルールがあり、リクエストから3秒以内にレスポンスがないとタイムアウト扱いになってしまうため、以下のコードのようにLazyリスナーを設定しました。

def handle_mention(event, say):
# 処理を書く

def just_ack(ack):
ack()

app.event("app_mention")(ack=just_ack, lazy=[handle_mention])

2. Slackのリトライを無視する

Cloud Runの性質上コールドスタートによって起動に時間がかかり、3秒ルールを破ってしまうことがあります。
Slackからのリクエストでタイムアウトした場合、リクエストが再送されてしまい処理が2重3重に立ち上がって返信を連投してしまいます。なので、ヘッダーにx-slack-retry-numがあればリクエストを無視する処理を追加しました。

FlastAPIの例

@api.post("/slack/events")
async def slack_endpoint(req: Request):
headers = req.headers
if "x-slack-retry-num" in headers:
logger.info(f"Skip x-slack-retry-num: {headers['x-slack-retry-num']}")
return

続いて、Cloud Runの設定について説明していきます。

3. 「サービスの最小インスタンスを1以上」、「リクエスト時にのみCPUを割り当てる」に設定する

コンソール上で「Cloud Run」の「サービスの詳細」を開いて、右上の方に「サービスの最小インスタンス数」があるのでそこを「1」以上に設定してください。

次に「新しいリビジョンの編集とデプロイ」から「CPU の割り当てと料金」で「リクエストの処理中にのみCPUを割り当てる」に設定してください。

これらの設定をすることで、インスタンスが常に稼働しつつもリクエストがない時はIdle状態になるので、コストを抑えながらも安定して稼働するようになりました。

以上です!

さいごに

誰かのお役に立てれば幸いです。