AWS SDK を使用して Lambda 関数を呼び出す際の再試行とタイムアウトの問題は、どのようにしてトラブルシューティングすればよいですか?

最終更新日: 2021 年 3 月 18 日

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 応答に時間がかかり過ぎた後に接続がタイムアウトしたエラーログの例 (接続タイムアウト)

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)

例えば、AWS SDK が 3 回の再試行、接続タイムアウトが 10 秒、ソケットタイムアウトが 30 秒に設定されているとします。その場合、Lambda 関数のタイムアウトには 160 秒以上の時間を確保します。

First attempt (10 seconds + 30 seconds) + Number of retries [3 * (10 seconds + 30 seconds)] = 160 seconds

残りのコードランタイムを処理するために、時間のマージン (例えば 20 秒) を追加します。

160 + 20 = 180 seconds

この記事はお役に立ちましたか?


請求に関するサポートまたは技術サポートが必要ですか?