Skip to content

Commit f251dd8

Browse files
committed
fix: improve aws client retry strategy
OTT-7367
1 parent 2b8b251 commit f251dd8

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

awsmt/provider.go

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package awsmt
33
import (
44
"context"
55
"github.com/aws/aws-sdk-go-v2/aws"
6+
"github.com/aws/aws-sdk-go-v2/aws/retry"
67
"github.com/aws/aws-sdk-go-v2/config"
78
"github.com/aws/aws-sdk-go-v2/service/mediatailor"
89
"github.com/hashicorp/terraform-plugin-framework/datasource"
@@ -12,6 +13,7 @@ import (
1213
"github.com/hashicorp/terraform-plugin-framework/types"
1314
"github.com/hashicorp/terraform-plugin-log/tflog"
1415
"os"
16+
"time"
1517
)
1618

1719
var (
@@ -25,8 +27,9 @@ func New() provider.Provider {
2527
type awsmtProvider struct{}
2628

2729
type awsmtProviderModel struct {
28-
Profile types.String `tfsdk:"profile"`
29-
Region types.String `tfsdk:"region"`
30+
Profile types.String `tfsdk:"profile"`
31+
Region types.String `tfsdk:"region"`
32+
MaxRetryAttempts types.Int64 `tfsdk:"max_retry_attempts"`
3033
}
3134

3235
func (p *awsmtProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
@@ -44,6 +47,10 @@ func (p *awsmtProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp
4447
Optional: true,
4548
Description: "AWS region. defaults to 'eu-central-1'.",
4649
},
50+
"max_retry_attempts": schema.Int64Attribute{
51+
Optional: true,
52+
Description: "The maximum number of times the provider will retry a failed aws operation. Defaults to 10",
53+
},
4754
},
4855
}
4956
}
@@ -60,6 +67,7 @@ func (p *awsmtProvider) Configure(ctx context.Context, req provider.ConfigureReq
6067

6168
var region = "eu-central-1"
6269
var profile = ""
70+
var maxAttempts = 10
6371

6472
var err error
6573
// New sdk version creation
@@ -68,23 +76,18 @@ func (p *awsmtProvider) Configure(ctx context.Context, req provider.ConfigureReq
6876
if !providerConfig.Region.IsUnknown() || !providerConfig.Region.IsNull() {
6977
region = providerConfig.Region.ValueString()
7078
}
71-
7279
if providerConfig.Profile.IsUnknown() || providerConfig.Profile.IsNull() || providerConfig.Profile.ValueString() == "" {
7380
if os.Getenv("AWS_PROFILE") != "" {
7481
profile = os.Getenv("AWS_PROFILE")
7582
}
7683
} else {
7784
profile = providerConfig.Profile.ValueString()
7885
}
79-
80-
tflog.Debug(ctx, "Creating AWS client session")
81-
82-
if profile != "" {
83-
cfg, err = config.LoadDefaultConfig(ctx, config.WithSharedConfigProfile(profile), config.WithRegion(region))
84-
} else {
85-
cfg, err = config.LoadDefaultConfig(ctx, config.WithRegion(region))
86+
if !providerConfig.MaxRetryAttempts.IsUnknown() || !providerConfig.MaxRetryAttempts.IsNull() {
87+
maxAttempts = int(providerConfig.MaxRetryAttempts.ValueInt64())
8688
}
87-
89+
tflog.Debug(ctx, "Creating AWS client session")
90+
cfg, err = p.getClientConfig(ctx, region, profile, maxAttempts)
8891
if err != nil {
8992
resp.Diagnostics.AddError("Failed to Initialize Provider in Region", "unable to initialize provider in the specified region: "+err.Error())
9093
return
@@ -98,6 +101,28 @@ func (p *awsmtProvider) Configure(ctx context.Context, req provider.ConfigureReq
98101
tflog.Info(ctx, "AWS MediaTailor client configured", map[string]any{"success": true})
99102
}
100103

104+
func (p *awsmtProvider) getClientConfig(ctx context.Context, region, profile string, maxAttempts int) (aws.Config, error) {
105+
backoff := customBackoff{
106+
minDelay: 500 * time.Millisecond,
107+
}
108+
retryer := retry.NewStandard(func(o *retry.StandardOptions) {
109+
o.Backoff = backoff
110+
o.MaxAttempts = maxAttempts
111+
o.MaxBackoff = 10 * time.Second
112+
})
113+
114+
var optFns []func(*config.LoadOptions) error
115+
optFns = append(optFns, config.WithRegion(region))
116+
optFns = append(optFns, config.WithRetryer(func() aws.Retryer {
117+
return retryer
118+
}))
119+
if profile != "" {
120+
optFns = append(optFns, config.WithSharedConfigProfile(profile))
121+
}
122+
123+
return config.LoadDefaultConfig(ctx, optFns...)
124+
}
125+
101126
func (p *awsmtProvider) DataSources(_ context.Context) []func() datasource.DataSource {
102127
return []func() datasource.DataSource{
103128
DataSourceChannel,
@@ -118,3 +143,16 @@ func (p *awsmtProvider) Resources(_ context.Context) []func() resource.Resource
118143
ResourceVodSource,
119144
}
120145
}
146+
147+
type customBackoff struct {
148+
minDelay time.Duration
149+
}
150+
151+
func (b customBackoff) BackoffDelay(attempt int, err error) (time.Duration, error) {
152+
jb := retry.NewExponentialJitterBackoff(10 * time.Second)
153+
standardDelay, stdErr := jb.BackoffDelay(attempt, err)
154+
if stdErr != nil {
155+
return 0, stdErr
156+
}
157+
return max(standardDelay, b.minDelay), nil
158+
}

docs/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ The AWSMT Provider supports the following argument:
4848

4949
- `profile` - (Optional) AWS configuration profile.
5050
You can find the profile(s) name in `~/.aws/config` (Mac & Linux) or `%USERPROFILE%\.aws\config` (Windows).
51+
52+
- `max_retry_attempts` - (Optional) Aws client maximum retries.
53+
Number, defaults to 10.

0 commit comments

Comments
 (0)