TL;DR
--cli-read-timeout オプションで0を設定するか、呼び出すLambda関数のタイムアウト時間の秒数を指定する。
事象
Lambda関数で60秒を超える処理を行った際に AWS CLI で InvocationType が RequestResponse なのにLambda関数が複数回呼び出される。
原因
AWS CLI の lambda invoke はデフォルトでは60秒間でタイムアウトし5回まで再実行されるため。
確認
以下のようなLambda関数を用意します。指定した秒数、スリープで停止するLambda関数です。Lambda関数名は sleep とします。
タイムアウト時間は900秒(15分)にでも設定しておいてください。
import json
import time
print('Loading function')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
sleep_seconds = int(event.get("sleep", 3))
time.sleep(sleep_seconds)
return "sleep: {}s".format(sleep_seconds)
AWS CLI でLambda関数を実行します。65秒停止するよう指定します。
--debug オプションでデバッグログを出力しています。
aws lambda invoke \
--function-name sleep \
--invocation-type 'RequestResponse' \
--payload '{"sleep":"65"}' \
--debug \
output.text
デバッグログを参照すると、接続タイムアウト設定を行なっていることが確認できます。
2020-07-10 10:26:47,915 - MainThread - botocore.endpoint - DEBUG - Setting lambda timeout as (60, 60)
さらにLambdaエンドポイントへ接続し、60秒後にタイムアウトが発生していることが分かります。
2020-07-10 10:26:47,938 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): lambda.ap-northeast-1.amazonaws.com:443
urllib3.exceptions.ReadTimeoutError: AWSHTTPSConnectionPool(host='lambda.ap-northeast-1.amazonaws.com', port=443): Read timed out. (read timeout=60)
タイムアウトでエラーとなると AWS CLI は再度Lambda関数を呼び出しています。
2020-07-10 10:27:49,004 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (2): lambda.ap-northeast-1.amazonaws.com:443
最大5回の実行が確認されました。
2020-07-10 10:30:52,431 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (5): lambda.ap-northeast-1.amazonaws.com:443
AWS CLI のレスポンスには以下が返ってきます。 output.text は出力されません。
尚、ここで2回目以降の実行が60秒以内に戻ってきた場合、正常終了のレスポンスが戻り output.text も正常に出力されるため、複数回呼び出されていることに気付きにくいことになります。
Read timeout on endpoint URL: "https://lambda.ap-northeast-1.amazonaws.com/2015-03-31/functions/sleep/invocations"
解決
--cli-read-timeout オプションを指定します。ここでは900秒を指定しましたが、0(無期限)でも構いません。
aws lambda invoke \
--function-name sleep \
--invocation-type 'RequestResponse' \
--payload '{"sleep":"65"}' \
--cli-read-timeout 900 \
--debug \
output.text
デバッグログを参照すると、接続タイムアウト設定に900秒が設定されていることが確認できます。
2020-07-10 10:42:16,834 - MainThread - botocore.endpoint - DEBUG - Setting lambda timeout as (60, 900)
AWS CLI のレスポンスも戻ってきて、output.text にも出力されています。
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
"sleep: 65s"
参考
コマンドラインオプション
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-options.html