掲題のやりかたについてちょっと調べたので、その内容をメモしておきます。
Lambda プロキシ統合とタイムアウト
API Gatewayから Lambda連携する際に、Lambda Proxy Integration(プロキシ統合)という機能を使用すると、 API GatewayからのLambda呼び出しと、そのリクエストとレスポンスをよろしくマッピングしてくれるので、いちいちマッピング定義を書かなくても LambdaとAPI Gatewayを連携できるのでよく使うのですが、Lambdaのタイムアウト(実行時間超過)の扱いについてちょっと困りました。
Lambda プロキシ統合を使用すると、統合レスポンスのマッピングが自動化されるので、個別に設定することができません。
さらに、LambdaがタイムアウトしたときのメッセージはLambda側でいじることができないので、API Gatewayからは
以下に説明されているような 502 不正な Lambda プロキシ応答
として認識されてしまい、 API Gateway呼び出し側からは非常に分かりづらい
ものとなってしまいます。
いろいろ試行錯誤しているうちに、以下のような方法で落ち着きました。
- API GatewayのLambda プロキシ統合使用時にLambdaのタイムアウトをハンドリングするのは諦めて、基本的に API Gatewayのタイムアウト時間 < Lambdaのタイムアウト時間 になるように設定する。
- 上記の設定により、Lambdaがタイムアウトする前に、API Gatewayが
504 Gateway Timeout
を返してくれるので、それで分かるようになる。
タイムアウトの検知
次に、Lambda or API GatewayでのタイムアウトをCloudWatchに書かれるログを見ながら、指定した時間枠に一定数以上発生すればアラートを投げるという処理を考えます。タイムアウトをログから検知する方法は以下の2通りが考えられます。
- Lambdaのログから検知する。Lambdaのタイムアウトメッセージは変更できないので、 "Task timed out after xxx" という文字列を引っ掛けてCloudWatchで集計する
- API Gateway の ログから検知する。 API Gateway がタイムアウトした場合は、 以下のような
504 Gateway Timeout
が記録されるので、このステータスと、resourcePath を使って、どこがタイムアウトしたかを検知する。
{ "requestId": "xxxx", .... "requestTime": "06/Feb/2020:10:32:29 +0000", "httpMethod": "GET", "resourcePath": "/test", "status": "504", }
また、API GatewayのログをCloudWatchへ書き込むには以下の手順を行う必要があり、デフォルトでは出力されません。
今回は後者のAPI Gatewayでのログ集計と検知を採用しました。理由としてはLambdaの変更できないメッセージを検索文字列として引っ掛けるのは気持ちが悪いのと、API GatewayとLambdaのタイムアウト時間は微妙に異なるので、Lambdaが応答返したけどAPI Gatewayはタイムアウトを返しているケースなどが拾えないなどがあるからです。
...と まあやってみると普通に至極当たり前のような内容を書いただけになっているかもしれませんが、一応調べてこういう内容になったということを記録として残しておきます。