起きたトラブル
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回くらいでちょうど良いのではないか(適当)。
import { DocumentClient } from 'aws-sdk/lib/dynamodb/document_client';
const dynamoClient: DocumentClient = new AWS.DynamoDB.DocumentClient({
httpOptions: {
timeout: 200,
},
maxRetries: 10,
});