Slackのスラッシュコマンドのタイムアウトエラー解消法

記事タイトルとURLをコピーする

プロセスエンジニアリング部の谷です。 外部サービスにログインせず、ほしい情報を手にすることができるというSlackのスラッシュコマンドを作りました。 Slackのスラッシュコマンドをサーバーレスで運用すると陥るタイムアウトエラーの解消方法をご説明します。

一応、構成図 f:id:swx-tani:20201007181942p:plain

3秒の壁

Slackではリクエストを投げてから3,000ms以内、つまり3秒以内にレスポンスが返ってこないとタイムアウトになってしまいます。

Slack APIhttps://api.slack.com/slash-commands#responding_to_commands

今回、外部APIを叩くため、どうしても時間がかかってしまいます。

解決方法

  1. スラッシュコマンドが実行されたら3秒以内にレスポンスを返す関数を別で作ります
  2. その関数が外部APIを叩く関数を呼び出します
  3. ほしい情報が送信されます

3秒以内にレスポンスは返っているので、ほしい情報を取得するのに時間がかかってもタイムアウトエラーは起こらないというわけです。

f:id:swx-tani:20201007184426p:plain

1.で呼び出される関数の作り方(フロント)

import urllib.request
from urllib.parse import parse_qs
import boto3
import json
import logging
 
logger = logging.getLogger()
logger.setLevel(logging.INFO)
 
def lambda_handler(event,context):
    print(event)
    params = event['body']
 
    input_event = {'user_id':params['user_id']}
    Payload = json.dumps(input_event)
    res = boto3.client('lambda').invoke(
      FunctionName='zendesk-csv-prod', # 2.で呼び出されるLambdaファンクション名を指定
      InvocationType='Event', # 非同期
      Payload=Payload
    )
    logger.info(res)
 
    return 'Please wait for about 1 minutes as it will be sent by DM'

ポイントは、InvocationTypeです。 Lambdaが呼び出されるイベントが同期なのか、非同期なのかを指定します。

■同期呼び出し(RequestResponse) キューイングされず直接Lambdaを1回実行します。 Lambdaが実行され、処理が完了してからレスポンスが返ってきます。(レスポンスに時間がかかってしまう)

■非同期呼び出し(Event) Lambdaを直接実行するのではなく、キューイングされた後、実行されます。 その際、キューイングされたタイミングでレスポンスが返ってきます。(レスポンスが早い)

スラッシュコマンド設定のURLに、フロントのAPI Gatewayのエンドポイントを入力すれば、タイムアウトエラーせずにほしい情報が送られてきます。

さいごに

Lambdaの呼び出しに同期と非同期があることを初めて知りました。 タイムアウトで困ったら、呼び出し部分を確認してみてください。 別の解消方法もあるみたいなのでそれは別の機会に。