View a markdown version of this page

再試行とタイムアウト - AWS SDK for Go v2

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

再試行とタイムアウト

AWS SDK for Go を使用すると、HTTP サービスへのリクエストの再試行動作を設定できます。デフォルトでは、サービスクライアントは retry.Standard をデフォルトのリトライヤとして使用します。デフォルトの設定や動作がアプリケーションの要件を満たさない場合は、リトライヤの設定を調整するか、独自のリトライヤ実装を提供できます。

AWS SDK for Go は、実装する再試行実装に必要なメソッドのセットを定義する aws.Retryer インターフェイスを提供します。SDK には、再試行用に retry.Standardaws.NoOpRetryer の 2 つの実装が用意されています。

標準リトライヤ

retry.Standard リトライヤは、SDK クライアントが使用するデフォルトの aws.Retryer 実装です。標準リトライヤは、レート制限付きの再試行方式を採用しており、最大試行回数を設定できるほか、リクエストのバックオフポリシーも調整できます。

次の表では、このリトライヤのデフォルト値を示しています。

プロパティ デフォルト

最大試行回数

3

最大バックオフ遅延

20 秒

リクエストの呼び出し時に再試行可能なエラーが発生すると、標準リトライヤは指定された設定に基づいてリクエストを遅延させた後、再試行します。再試行により、リクエストの全体的なレイテンシーが長くなります。そのため、デフォルトの設定がアプリケーションの要件に合わない場合は、リトライヤを設定する必要があります。

標準リトライヤ実装で再試行可能と判断されるエラーの詳細については、retry パッケージのドキュメントを参照してください。

NopRetryer

aws.NopRetryer は、すべての再試行を無効にするために用意されている aws.Retryer 実装です。このリトライヤを使用すると、サービスクライアントのオペレーションは 1 回だけ試行され、エラーが発生した場合は呼び出し元のアプリケーションにそのまま返されます。

動作のカスタマイズ

SDK は aws.Retryer 実装をラップするためのヘルパーユーティリティ群を提供しており、必要な再試行動作を適用したリトライヤを返します。デフォルトのリトライヤは、アプリケーションの要件に応じて、すべてのクライアント、個別のクライアント、またはオペレーション単位でオーバーライドできます。これを行う方法を示すその他の例については、retry パッケージのドキュメントの例を参照してください。

警告

config.WithRetryer を使用してグローバルな aws.Retryer 実装を指定する場合は、呼び出しごとに新しい aws.Retryer インスタンスを返すようにする必要があります。これにより、すべてのサービスクライアント間でグローバルな再試行トークンバケットが作成されなくなります。

最大試行回数の制限

retry.AddWithMaxAttempts を使用して aws.Retryer 実装をラップし、最大試行回数を必要な値に設定します。

警告

retry.AddWithMaxAttempts に 0 を指定すると、SDK はリクエストが成功するか、再試行不能なエラーが返されるまで、すべての再試行可能なエラーに対してリクエストを再試行できます。SDK に無限の再試行を許可すると、ワークロードが暴走し、請求サイクルが増大する可能性があります。

import "context" import "github.com/aws/aws-sdk-go-v2/aws/retry" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" // ... // MaxAttempts will be infinite (will retry indefinitely) cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(func() aws.Retryer { return retry.AddWithMaxAttempts(retry.NewStandard(), 0) })) if err != nil { return err } client := s3.NewFromConfig(cfg)

関数型オプションを使用して MaxAttempts を直接設定してリトライヤをインスタンス化する場合、動作はわずかに異なります。具体的には、0 以下の値を設定すると、無限の再試行ではなく、デフォルトの最大 3 回の再試行が使用されます。

import "context" import "github.com/aws/aws-sdk-go-v2/aws/retry" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" // ... // MaxAttempts will default to 3 cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(func() aws.Retryer { return retry.NewStandard(func(o *retry.StandardOptions) { o.MaxAttempts = 0 }) })) if err != nil { return err } client := s3.NewFromConfig(cfg)

最大バックオフ遅延の制限

retry.AddWithMaxBackoffDelay を使用して aws.Retryer 実装をラップし、失敗したリクエストの再試行間に発生する最大バックオフ遅延を制限できます。

例えば、次のコードを使用して、標準クライアントのリトライヤに 5 秒の最大遅延を設定できます。

import "context" import "time" import "github.com/aws/aws-sdk-go-v2/aws/retry" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" // ... cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(func() aws.Retryer { return retry.AddWithMaxBackoffDelay(retry.NewStandard(), time.Second*5) })) if err != nil { return err } client := s3.NewFromConfig(cfg)

追加の API エラーコードを再試行する

retry.AddWithErrorCodes を使用すると、aws.Retryer 実装をラップして、再試行可能と見なす追加の API エラーコードを指定できます。

例えば、次のコードを使用して、標準クライアントリトライヤをラップし、Amazon S3 の NoSuchBucketException 例外を再試行可能として含めることができます。

import "context" import "time" import "github.com/aws/aws-sdk-go-v2/aws/retry" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" import "github.com/aws/aws-sdk-go-v2/service/s3/types" // ... cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(func() aws.Retryer { return retry.AddWithErrorCodes(retry.NewStandard(), (*types.NoSuchBucketException)(nil).ErrorCode()) })) if err != nil { return err } client := s3.NewFromConfig(cfg)

クライアント側のレート制限

では、最新の SDK の動作に合わせて、標準の再試行ポリシーに新しいクライアント側のレート制限メカニズム AWS SDK for Go が導入されています。 SDKs この動作は、リトライヤの options にある RateLimiter フィールドによって制御されます。

RateLimiter は、容量を設定されたトークンバケットとして動作し、オペレーションの試行失敗によりトークンを消費します。トークンが不足している状態で再試行を試みると、そのオペレーションは QuotaExceededError により失敗します。

デフォルトの実装では、次のようにパラメータ化されています (各設定値の変更方法を示す例も示しています)。

  • 容量は 500 (NewTokenRateLimit を使用して StandardOptions の RateLimiter の値を設定)

  • タイムアウトによる再試行は 10 トークンを消費 (StandardOptions の RetryTimeoutCost を設定)

  • その他のエラーによる再試行は 5 トークンを消費 (StandardOptions の RetryCost を設定)

  • 最初の試行で成功したオペレーションは 1 トークンを追加 (StandardOptions の NoRetryIncrement を設定)

    • 2 回目以降の試行で成功したオペレーションはトークンを追加しない

デフォルトの動作がアプリケーションの要件に合わない場合は、ratelimit.None を使用してレート制限を無効にできます。

例: レート制限を変更

import ( "context" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/ratelimit" "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/config" ) // ... cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRetryer(func() aws.Retryer { return retry.NewStandard(func(o *retry.StandardOptions) { // Makes the rate limiter more permissive in general. These values are // arbitrary for demonstration and may not suit your specific // application's needs. o.RateLimiter = ratelimit.NewTokenRateLimit(1000) o.RetryCost = 1 o.RetryTimeoutCost = 3 o.NoRetryIncrement = 10 }) }))

例: ratelimit.None を使用してレート制限なしに変更

import ( "context" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/ratelimit" "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/config" ) // ... cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRetryer(func() aws.Retryer { return retry.NewStandard(func(o *retry.StandardOptions) { o.RateLimiter = ratelimit.None }) }))

タイムアウト

サービスクライアントのオペレーションを呼び出す際には、context パッケージを使用してタイムアウトやデッドラインを設定します。context.WithDeadline を使用してアプリケーションのコンテキストをラップし、呼び出したオペレーションを完了する必要がある特定の時間に期限を設定します。一定時間 time.Duration 後にタイムアウトを設定するには、context.WithTimeout を使用します。SDK は、渡された context.Context をサービス API の呼び出し時に HTTP トランスポートクライアントに渡します。SDK に渡したコンテキストが既にキャンセルされている、または呼び出し中にキャンセルされた場合、SDK はそれ以上リクエストを再試行せず、呼び出し元アプリケーションに制御を戻します。そのため、SDK に渡すコンテキストがキャンセルされた場合に備えて、アプリケーション側で適切なキャンセル処理を実装する必要があります。

タイムアウトの設定

次の例では、サービスクライアントのオペレーションにタイムアウトを設定する方法を示しています。

import "context" import "time" // ... ctx := context.TODO() // or appropriate context.Context value for your application client := s3.NewFromConfig(cfg) // create a new context from the previous ctx with a timeout, e.g. 5 seconds ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() resp, err := client.GetObject(ctx, &s3.GetObjectInput{ // input parameters }) if err != nil { // handle error }