【AWS】LambdaからDynamoDBを呼ぶときは、タイムアウト時間を設定変更しようの巻


起きたトラブル

APIGW <-> Lambda <-> DynamoDBのようなシンプルな構成で、DBの中身をサーバレス配信するようなAPIを作ったとき、ごくまれにLambdaがタイムアウトを起こした。Lambdaのランタイムはnodejs。

↓ランダムに大量リクエストを飛ばしてみると、全体の0.1%未満ながら、間違いなく5秒タイムアウトしている🤮

Lambdaのタイムアウト時間は自由に設定変更できるが、30秒タイムアウトに設定しても改善しない。
(そもそも30秒もかかっていたら使い物にならないけど。)

なにがまずいのか

aws-sdkの仕様書より抜粋↓

timeout [Integer] — Sets the socket to timeout after timeout milliseconds of inactivity on the socket. Defaults to two minutes (120000).
(https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#constructor-property)

JavaScript版のaws-sdkでは、DynamoDBのソケットタイムアウト時間がデフォルトで120000ms ( 2分間🤮 ) に設定されている。
すなわち、一度詰まってしまうと2分経過するまでDynamoDBへの通信をリトライしてくれない。
その結果、リトライ処理が呼ばれる前にLambdaがタイムアウトしてしまっていた。

こうなるとLambda内でエラーハンドルしていたとしても強制終了されてしまうため、ログにも現れないまま謎のタイムアウトとして処理されてしまう。

解決策

デフォルトで設定されているタイムアウト時間 (120000ms) を設定変更してやれば良い。
DynamoDBのDocumentClientを生成するタイミングでhttpOptionsとして引数を渡せば、デフォルト設定を上書きできる。
Lambdaのタイムアウト設定が5秒なら、ソケットタイムアウト200ms & リトライ上限10回くらいでちょうど良いのではないか(適当)。

sample.ts
import { DocumentClient } from 'aws-sdk/lib/dynamodb/document_client';

const dynamoClient: DocumentClient = new AWS.DynamoDB.DocumentClient({
  httpOptions: {
    timeout: 200,
  },
  maxRetries: 10,
});