何度もレスポンスする事例
前の記事で、slack botをAWS lambdaを使って作成しましたが、それの最後に述べたように、何度か同じレスポンスをしてしまう場合があります。
これはslackのタイムアウト時間が3秒しかなく、3秒以内にレスポンスできないとエラーと見なされ、何度か同じイベントを送ってくるため、それに対してlambda関数が何度か呼ばれてしまうことが原因です。
解決方法
新しいlambda関数を作成し、そこから非同期でslackにpostするlambda関数を呼び出すことにする!
このようにすれば、slack APIへのレスポンスは新しいlambda関数からすぐに行うことができ、そのあとでゆっくりとワークスペースにpostMessageすることができます。
新しいlambda関数の作成
IAMロールの作成
前回の記事と同じ手順でロールを作成します。
今回はロールの名前をinvokeBotRole
としました。
前回と異なるのは、Permissions PoliciesにAWSLambdaBasicExecutionRole
の他にAWSLambdaRole
を追加してください。これによって他のlambda関数を呼び出すことが可能になります。
lambda関数の作成
前回の記事ではJava縛りで作成しましたが、今回はサクッとPython3.7で作っていきます。
lambdaのページで以下のように設定して、invokeBot
というlambda関数を作成しました。
API Gatewayの作成
これも前回の記事と同様に作成していきます。
今回は、invokeBotAPI
という名前のAPIGatewayにして、デプロイ時のステージ名はinvokeBotStage
としました。
デプロイ時に表示されるURLをメモしておくのを忘れないでください。
lambda関数の編集
再びlambda関数のページに戻って編集していきます。
API Gatewayから入って、他のlambda関数に接続できるようになっていることが確認できると思います。
lambda関数を以下のように編集します。
-
FunctionName='sampleBot'
の部分で呼び出すlambda関数の名前を設定しています -
InvocationType='Event'
とすることで非同期の実行が可能になります - Slack Event APIの認証にも対応できるようにしています
import json
import boto3
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event: dict, context):
logging.info(json.dumps(event))
if "challenge" in event:
return event.get("challenge")
client = boto3.client('lambda')
response = client.invoke(
FunctionName='sampleBot',
InvocationType='Event',
LogType='Tail',
Payload= json.dumps(event)
)
return {
'statusCode': 200,
'body': json.dumps('OK')
}
また、一応念の為lambda関数のtimeout時間も3秒に設定しておくと、確実に3秒以内にslack APIにレスポンスが送られるため安全です。
イベントのRequest URLに設定
slack APIが呼び出すURLを新しいURLに変更しましょう
先ほどのAPIのデプロイ時にメモしておいたURLを設定し直します
動作確認
参考
AWS LambdaからLambda呼んでハマった話。
AccessDeniedException: User is not authorized to perform: lambda:InvokeFunction