Skip to content

Commit

Permalink
Change aws.Config#Retryer to be a value provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
skmcgrail committed Jan 12, 2021
1 parent e958265 commit 4ab10e1
Show file tree
Hide file tree
Showing 14 changed files with 53 additions and 26 deletions.
11 changes: 8 additions & 3 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ type Config struct {
// service and region Please see the `aws.EndpointResolver` documentation on usage.
EndpointResolver EndpointResolver

// Retryer guides how HTTP requests should be retried in case of
// recoverable failures. When nil the API client will use a default
// Retryer is a function that provides a Retryer implementation. A Retryer guides how HTTP requests should be
// retried in case of recoverable failures. When nil the API client will use a default
// retryer.
Retryer Retryer
//
// In general, the provider function should return a new instance of a Retyer if you are attempting
// to provide a consistent Retryer configuration across all clients. This will ensure that each client will be
// provided a new instance of the Retryer implementation, and will avoid issues such as sharing the same retry token
// bucket across services.
Retryer func() Retryer

// ConfigSources are the sources that were used to construct the Config.
// Allows for additional configuration to be loaded by clients.
Expand Down
8 changes: 5 additions & 3 deletions aws/retry/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import (
)

func Example_overrideForAllClients() {
custom := retry.AddWithMaxBackoffDelay(retry.NewStandard(), time.Second*5)

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(custom))
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(func() aws.Retryer {
// Generally you will always want to return new instance of a Retryer. This will avoid a global rate limit
// bucket being shared between across all service clients.
return retry.AddWithMaxBackoffDelay(retry.NewStandard(), time.Second*5)
}))
if err != nil {
log.Fatal(err)
return
Expand Down
2 changes: 1 addition & 1 deletion aws/retry/internal/mock/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Options struct {
Retryer aws.Retryer
}

// Options is a mock Client
// Client is a mock service client
type Client struct{}

// GetObjectInput is mock input
Expand Down
2 changes: 1 addition & 1 deletion aws/retry/internal/mock/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ func LoadDefaultConfig(context.Context, ...func()) (cfg aws.Config, err error) {
}

// WithRetryer is a mock for config.WithRetryer
func WithRetryer(v aws.Retryer) (f func()) {
func WithRetryer(v func() aws.Retryer) (f func()) {
return f
}
10 changes: 5 additions & 5 deletions config/load_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ type LoadOptions struct {
// service and region Please see the `aws.EndpointResolver` documentation on usage.
EndpointResolver aws.EndpointResolver

// Retryer guides how HTTP requests should be retried in case of
// recoverable failures.
Retryer aws.Retryer
// Retryer is a function that provides a Retryer implementation. A Retryer guides how HTTP requests should be
// retried in case of recoverable failures.
Retryer func() aws.Retryer

// APIOptions provides the set of middleware mutations modify how the API
// client requests will be handled. This is useful for adding additional
Expand Down Expand Up @@ -477,7 +477,7 @@ func WithAPIOptions(v []func(*middleware.Stack) error) LoadOptionsFunc {
}
}

func (o LoadOptions) getRetryer(ctx context.Context) (aws.Retryer, bool, error) {
func (o LoadOptions) getRetryer(ctx context.Context) (func() aws.Retryer, bool, error) {
if o.Retryer == nil {
return nil, false, nil
}
Expand All @@ -489,7 +489,7 @@ func (o LoadOptions) getRetryer(ctx context.Context) (aws.Retryer, bool, error)
// that sets Retryer on LoadOptions. If Retryer is set to nil, the
// Retryer value is ignored. If multiple WithRetryer calls are
// made, the last call overrides the previous call values.
func WithRetryer(v aws.Retryer) LoadOptionsFunc {
func WithRetryer(v func() aws.Retryer) LoadOptionsFunc {
return func(o *LoadOptions) error {
o.Retryer = v
return nil
Expand Down
4 changes: 2 additions & 2 deletions config/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,10 @@ func getClientLogMode(ctx context.Context, configs configs) (m aws.ClientLogMode

// retryProvider is an configuration provider for custom Retryer.
type retryProvider interface {
getRetryer(ctx context.Context) (aws.Retryer, bool, error)
getRetryer(ctx context.Context) (func() aws.Retryer, bool, error)
}

func getRetryer(ctx context.Context, configs configs) (v aws.Retryer, found bool, err error) {
func getRetryer(ctx context.Context, configs configs) (v func() aws.Retryer, found bool, err error) {
for _, c := range configs {
if p, ok := c.(retryProvider); ok {
v, found, err = p.getRetryer(ctx)
Expand Down
13 changes: 9 additions & 4 deletions config/resolve_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ func resolveHTTPCredProvider(ctx context.Context, cfg *aws.Config, url, authToke
options.AuthorizationToken = authToken
}
options.APIOptions = cfg.APIOptions
options.Retryer = cfg.Retryer
if cfg.Retryer != nil {
options.Retryer = cfg.Retryer()
}
},
}

Expand Down Expand Up @@ -258,10 +260,13 @@ func resolveEC2RoleCredentials(ctx context.Context, cfg *aws.Config, configs con
optFns = append(optFns, func(o *ec2rolecreds.Options) {
// Only define a client from config if not already defined.
if o.Client != nil {
o.Client = imds.New(imds.Options{
options := imds.Options{
HTTPClient: cfg.HTTPClient,
Retryer: cfg.Retryer,
})
}
if cfg.Retryer != nil {
options.Retryer = cfg.Retryer()
}
o.Client = imds.New(options)
}
})

Expand Down
5 changes: 4 additions & 1 deletion feature/ec2/imds/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ func NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client {
opts := Options{
APIOptions: append([]func(*middleware.Stack) error{}, cfg.APIOptions...),
HTTPClient: cfg.HTTPClient,
Retryer: cfg.Retryer,
}

if cfg.Retryer != nil {
opts.Retryer = cfg.Retryer()
}

return New(opts, optFns...)
Expand Down
4 changes: 3 additions & 1 deletion service/apigateway/internal/customizations/unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ func Test_EmptyResponse(t *testing.T) {
SigningName: "apigateway",
}, nil
}),
Retryer: aws.NopRetryer{},
Retryer: func() aws.Retryer {
return aws.NopRetryer{}
},
}

client := apigateway.NewFromConfig(cfg)
Expand Down
4 changes: 3 additions & 1 deletion service/ec2/internal/customizations/unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ func Test_EmptyResponse(t *testing.T) {
SigningName: "ec2",
}, nil
}),
Retryer: aws.NopRetryer{},
Retryer: func() aws.Retryer {
return aws.NopRetryer{}
},
}

client := ec2.NewFromConfig(cfg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ func TestCustomErrorDeserialization(t *testing.T) {
SigningName: "route53",
}, nil
}),
Retryer: aws.NopRetryer{},
Retryer: func() aws.Retryer {
return aws.NopRetryer{}
},
})
resp, err := svc.ChangeResourceRecordSets(context.Background(), &route53.ChangeResourceRecordSetsInput{
ChangeBatch: &types.ChangeBatch{
Expand Down
4 changes: 3 additions & 1 deletion service/route53/internal/customizations/sanitizeurl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ func TestSanitizeURLMiddleware(t *testing.T) {
t.Run(name, func(t *testing.T) {
cfg := aws.Config{
Credentials: unit.StubCredentialsProvider{},
Retryer: aws.NopRetryer{},
Retryer: func() aws.Retryer {
return aws.NopRetryer{}
},
Region: "mock-region",
}

Expand Down
4 changes: 3 additions & 1 deletion service/s3/internal/customizations/presign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ func TestPutObject_PresignURL(t *testing.T) {
cfg := aws.Config{
Region: "us-west-2",
Credentials: unit.StubCredentialsProvider{},
Retryer: aws.NopRetryer{},
Retryer: func() aws.Retryer {
return aws.NopRetryer{}
},
}
presignClient := s3.NewPresignClient(s3.NewFromConfig(cfg), func(options *s3.PresignOptions) {
options = &c.options
Expand Down
4 changes: 3 additions & 1 deletion service/s3/internal/customizations/unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ func Test_EmptyResponse(t *testing.T) {
SigningName: "s3",
}, nil
}),
Retryer: aws.NopRetryer{},
Retryer: func() aws.Retryer {
return aws.NopRetryer{}
},
}

client := s3.NewFromConfig(cfg, func(options *s3.Options) {
Expand Down

0 comments on commit 4ab10e1

Please sign in to comment.