Rso's Jotter

日々の開発の知見のメモやその他雑記

AWS API GatewayのLambda Proxy Integration 使用時にLambdaのタイムアウトとその検知の扱い

掲題のやりかたについてちょっと調べたので、その内容をメモしておきます。

Lambda プロキシ統合とタイムアウト

API Gatewayから Lambda連携する際に、Lambda Proxy Integration(プロキシ統合)という機能を使用すると、 API GatewayからのLambda呼び出しと、そのリクエストとレスポンスをよろしくマッピングしてくれるので、いちいちマッピング定義を書かなくても LambdaとAPI Gatewayを連携できるのでよく使うのですが、Lambdaのタイムアウト(実行時間超過)の扱いについてちょっと困りました。

Lambda プロキシ統合を使用すると、統合レスポンスのマッピングが自動化されるので、個別に設定することができません。 さらに、LambdaがタイムアウトしたときのメッセージはLambda側でいじることができないので、API Gatewayからは 以下に説明されているような 502 不正な Lambda プロキシ応答 として認識されてしまい、 API Gateway呼び出し側からは非常に分かりづらい ものとなってしまいます。

aws.amazon.com

いろいろ試行錯誤しているうちに、以下のような方法で落ち着きました。

  • 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へ書き込むには以下の手順を行う必要があり、デフォルトでは出力されません。

aws.amazon.com

今回は後者のAPI Gatewayでのログ集計と検知を採用しました。理由としてはLambdaの変更できないメッセージを検索文字列として引っ掛けるのは気持ちが悪いのと、API GatewayとLambdaのタイムアウト時間は微妙に異なるので、Lambdaが応答返したけどAPI Gatewayはタイムアウトを返しているケースなどが拾えないなどがあるからです。

...と まあやってみると普通に至極当たり前のような内容を書いただけになっているかもしれませんが、一応調べてこういう内容になったということを記録として残しておきます。