AWS SDK を使用して AWS Lambda 関数を呼び出す際に、関数がタイムアウトするか、API リクエストが応答を停止するか、API アクションが重複します。これらの問題の解決方法を教えてください。
簡単な説明
AWS SDK で Lambda 関数を呼び出す際に、再試行とタイムアウトの問題が発生する理由としては、以下の 3 つが考えられます。
- リモート API に到達できないか、API 呼び出しに応答するのに時間がかかり過ぎている。
- ソケットがタイムアウトするまで、API 呼び出しが応答を受け取れなかった。
- API 呼び出しが Lambda 関数のタイムアウト期間内に応答を取得しない。
注: ネットワーク接続で問題が発生すると、API 呼び出しに想定より長い時間がかかることがあります。ネットワークの問題も、再試行や重複した API リクエストを引き起こす可能性があります。これらの発生に備えるために、Lambda 関数がべき等であることを確認してください。
AWS SDK を使用して API コールを行い、その呼び出しが失敗した場合、AWS SDK は自動的に呼び出しを再試行します。AWS SDK の再試行回数、およびその再試行時間は、各 AWS SDK で異なる設定によって決まります。
AWS SDK の再試行のデフォルト設定
注: 他の AWS のサービスについては、一部の値が異なる場合があります。
| | | |
---|
AWS SDK | 最大再試行回数 | 接続タイムアウト | ソケットタイムアウト |
Python (Boto 3) | サービスにより異なる | 60 秒 | 60 秒 |
JavaScript/Node.js | サービスにより異なる | 該当なし | 120 秒 |
Java | 3 | 10 秒 | 50 秒 |
.NET | 4 | 100 秒 | 300 秒 |
Go | 3 | 該当なし | 該当なし |
再試行とタイムアウトの問題をトラブルシューティングするには、最初に API コールのログを確認して、問題を見つけます。その後、各ユースケースの必要性に合わせて AWS SDK の再試行回数とタイムアウトの設定を変更します。API コールが応答するのに十分な時間を確保するには、[Lambda function timeout setting] (Lambda 関数のタイムアウト設定) で時間を追加します。
解決方法
AWS SDK により行われた API コールをログに記録する
Amazon CloudWatch Logs を使用して、失敗した接続の詳細と、それぞれの試みられた再試行回数の詳細を取得します。詳細については、「AWS Lambda の Amazon CloudWatch Logs へのアクセス」を参照してください。または、使用している AWS SDK についての次の指示をご確認ください。
API コールが接続を確立できなかったエラーログの例 (接続タイムアウト)
START RequestId: b81e56a9-90e0-11e8-bfa8-b9f44c99e76d Version: $LATEST
2018-07-26T14:32:27.393Z b81e56a9-90e0-11e8-bfa8-b9f44c99e76d [AWS ec2 undefined 40.29s 3 retries] describeInstances({})
2018-07-26T14:32:27.393Z b81e56a9-90e0-11e8-bfa8-b9f44c99e76d { TimeoutError: Socket timed out without establishing a connection
...
API コールの接続は成功したが、API レスポンスに時間がかかりすぎた後にタイムアウトしたエラーログの例 (ソケットタイムアウト)
START RequestId: 3c0523f4-9650-11e8-bd98-0df3c5cf9bd8 Version: $LATEST
2018-08-02T12:33:18.958Z 3c0523f4-9650-11e8-bd98-0df3c5cf9bd8 [AWS ec2 undefined 30.596s 3 retries] describeInstances({})
2018-08-02T12:33:18.978Z 3c0523f4-9650-11e8-bd98-0df3c5cf9bd8 { TimeoutError: Connection timed out after 30s
注: Lambda 関数がタイムアウトするまでに API リクエストが応答を取得できなかったときは、これらのログは生成されません。関数のタイムアウトが原因で API リクエストが終了する場合は、以下のいずれかを試してください。
AWS SDK の設定を変更する
AWS SDK の再試行回数とタイムアウト設定では API 呼び出しが応答を受け取るのに十分な時間が確保されていなければなりません。各設定に適切な値を判別するには、さまざまな設定をテストして、次の情報を取得します。
- 正常な接続が確立されるまでの平均時間
- 完全な API リクエストにかかる (正常に応答が戻るまでの) 平均時間
- AWS SDK またはコードで再試行を行う必要があるか
再試行回数およびタイムアウトの設定の変更の詳細については、次の AWS SDK クライアント設定ドキュメントをご参照ください。
各ランタイムの再試行回数およびタイムアウトの設定を変更するコマンドの例をいくつか次に示します。
重要: 次のいずれかのコマンドを使用する前に、各設定のサンプル値をご自身のユースケースで適切な値に置き換えてください。
再試行回数およびタイムアウトの設定を変更する Python (Boto 3) コマンドの例
# max_attempts: retry count / read_timeout: socket timeout / connect_timeout: new connection timeout
from botocore.session import Session
from botocore.config import Config
s = Session()
c = s.create_client('s3', config=Config(connect_timeout=5, read_timeout=60, retries={'max_attempts': 2}))
再試行回数およびタイムアウトの設定を変更する JavaScript/Node.js コマンドの例
// maxRetries: retry count / timeout: socket timeout / connectTimeout: new connection timeout
var AWS = require('aws-sdk');
AWS.config.update({
maxRetries: 2,
httpOptions: {
timeout: 30000,
connectTimeout: 5000
}
});
再試行回数およびタイムアウトの設定を変更する Java コマンドの例
// setMaxErrorRetry(): retry count / setSocketTimeout(): socket timeout / setConnectionTimeout(): new connection timeout
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setSocketTimeout(60000);
clientConfig.setConnectionTimeout(5000);
clientConfig.setMaxErrorRetry(2);
AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(credentialsProvider,clientConfig);
再試行回数およびタイムアウトの設定を変更する.NET コマンドの例
// MaxErrorRetry: retry count / ReadWriteTimeout: socket timeout / Timeout: new connection timeout
var client = new AmazonS3Client(
new AmazonS3Config {
Timeout = TimeSpan.FromSeconds(5),
ReadWriteTimeout = TimeSpan.FromSeconds(60),
MaxErrorRetry = 2
});
再試行回数の設定を変更する Go コマンドの例
// Create Session with MaxRetry configuration to be shared by multiple service clients.
sess := session.Must(session.NewSession(&aws.Config{
MaxRetries: aws.Int(3),
}))
// Create S3 service client with a specific Region.
svc := s3.New(sess, &aws.Config{
Region: aws.String("us-west-2"),
})
リクエストのタイムアウト設定を変更する Go コマンドの例
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// SQS ReceiveMessage
params := &sqs.ReceiveMessageInput{ ... }
req, resp := s.ReceiveMessageRequest(params)
req.HTTPRequest = req.HTTPRequest.WithContext(ctx)
err := req.Send()
(オプション) Lambda 関数のタイムアウト設定を変更する
Lambda 関数のタイムアウトを低く設定すると、正常の接続が早期に失われる可能性があります。ご自身のユースケースでこのような状況が発生するときは、関数のタイムアウト設定を増やして、API 呼び出しが応答を受け取るのに十分な時間を確保できるようにします。
次の式を使用して、関数のタイムアウトに必要な基礎時間を推定します。
First attempt (connection timeout + socket timeout) + Number of retries x (connection timeout + socket timeout) + 20 seconds additional code runtime margin = Required Lambda function timeout
Lambda 関数のタイムアウト計算の例
注: 次の計算は、3 回の再試行、10 秒の接続タイムアウト、および 30 秒のソケットタイムアウトに設定された AWS SDK の計算です。
First attempt (10 seconds + 30 seconds) + Number of retries [3 * (10 seconds + 30 seconds)] + 20 seconds additional code runtime margin = 180 seconds
関連情報
呼び出し (Lambda API リファレンス)
エラー処理と AWS Lambda での自動再試行
Lambda クォータ