Skip to content

Commit 56185a8

Browse files
committed
Merge branch 'b-prototype-new-retryer' into b-aws_instance.RunInstances-retry
2 parents 978afab + 42bfa85 commit 56185a8

File tree

6 files changed

+48
-49
lines changed

6 files changed

+48
-49
lines changed

.teamcity/scripts/provider_tests/acceptance_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ TF_ACC=1 go test \
5555
./internal/provider/... \
5656
./internal/reflect/... \
5757
./internal/retry/... \
58-
./internal/retry2/... \
58+
./internal/backoff/... \
5959
./internal/sdkv2/... \
6060
./internal/semver/... \
6161
./internal/slices/... \

.teamcity/scripts/provider_tests/unit_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set -euo pipefail
77
go test \
88
./internal/acctest/... \
99
./internal/attrmap/... \
10+
./internal/backoff/... \
1011
./internal/conns/... \
1112
./internal/create/... \
1213
./internal/dns/... \
@@ -27,7 +28,6 @@ go test \
2728
./internal/provider/... \
2829
./internal/reflect/... \
2930
./internal/retry/... \
30-
./internal/retry2/... \
3131
./internal/sdkv2/... \
3232
./internal/semver/... \
3333
./internal/slices/... \

internal/retry2/retry.go renamed to internal/backoff/backoff.go

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) HashiCorp, Inc.
22
// SPDX-License-Identifier: MPL-2.0
33

4-
package retry2
4+
package backoff
55

66
import (
77
"context"
@@ -20,7 +20,7 @@ type Timer interface {
2020
// DelayFunc returns the duration to wait before the next retry attempt.
2121
type DelayFunc func(uint) time.Duration
2222

23-
// FixedDelay returns a delay that is the same through all iterations except the first (when it is 0).
23+
// FixedDelay returns a delay. The first retry attempt has no delay (0), and subsequent attempts use the fixed delay.
2424
func FixedDelay(delay time.Duration) DelayFunc {
2525
return func(n uint) time.Duration {
2626
if n == 0 {
@@ -35,21 +35,24 @@ func FixedDelay(delay time.Duration) DelayFunc {
3535
// to pick the same deterministic random sequence.
3636
var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
3737

38-
// ExponentialBackoffWithJitterDelay returns a duration of backoffMinDuration * backoffMultiplier**n, with added jitter.
39-
func ExponentialBackoffWithJitterDelay(backoffMinDuration time.Duration, backoffMultiplier float64) DelayFunc {
38+
// ExponentialJitterBackoff returns a duration of backoffMinDuration * backoffMultiplier**n, with added jitter.
39+
func ExponentialJitterBackoff(backoffMinDuration time.Duration, backoffMultiplier float64) DelayFunc {
4040
return func(n uint) time.Duration {
4141
if n == 0 {
4242
return 0
4343
}
4444

4545
mult := math.Pow(backoffMultiplier, float64(n))
46-
d := time.Duration(float64(backoffMinDuration) * mult)
47-
const jitter = 0.4
48-
mult = 1 - jitter*rng.Float64() // Subtract up to 40%.
49-
return time.Duration(float64(d) * mult)
46+
return applyJitter(time.Duration(float64(backoffMinDuration) * mult))
5047
}
5148
}
5249

50+
func applyJitter(base time.Duration) time.Duration {
51+
const jitterFactor = 0.4
52+
jitter := 1 - jitterFactor*rng.Float64() // Subtract up to 40%.
53+
return time.Duration(float64(base) * jitter)
54+
}
55+
5356
type sdkv2HelperRetryCompatibleDelay struct {
5457
minTimeout time.Duration
5558
pollInterval time.Duration
@@ -105,20 +108,20 @@ func DefaultSDKv2HelperRetryCompatibleDelay() DelayFunc {
105108
return SDKv2HelperRetryCompatibleDelay(0, 0, 500*time.Millisecond) //nolint:mnd // 500ms is the Plugin SDKv2 default
106109
}
107110

108-
// Config configures a retry loop.
109-
type Config struct {
111+
// RetryConfig configures a retry loop.
112+
type RetryConfig struct {
110113
delay DelayFunc
111114
gracePeriod time.Duration
112115
timer Timer
113116
}
114117

115118
// Option represents an option for retry.
116-
type Option func(*Config)
119+
type Option func(*RetryConfig)
117120

118-
func emptyOption(c *Config) {}
121+
func emptyOption(c *RetryConfig) {}
119122

120123
func WithGracePeriod(d time.Duration) Option {
121-
return func(c *Config) {
124+
return func(c *RetryConfig) {
122125
c.gracePeriod = d
123126
}
124127
}
@@ -128,7 +131,7 @@ func WithDelay(d DelayFunc) Option {
128131
return emptyOption
129132
}
130133

131-
return func(c *Config) {
134+
return func(c *RetryConfig) {
132135
c.delay = d
133136
}
134137
}
@@ -137,7 +140,7 @@ func WithDelay(d DelayFunc) Option {
137140
// This primarily is useful for mocking/testing, where you may not want to explicitly wait for a set duration
138141
// for retries.
139142
func WithTimer(t Timer) Option {
140-
return func(c *Config) {
143+
return func(c *RetryConfig) {
141144
c.timer = t
142145
}
143146
}
@@ -149,53 +152,49 @@ func (t *timerImpl) After(d time.Duration) <-chan time.Time {
149152
return time.After(d)
150153
}
151154

152-
// The default Config is backwards compatible with github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.
153-
func defaultConfig() Config {
154-
return Config{
155+
// The default RetryConfig is backwards compatible with github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.
156+
func defaultRetryConfig() RetryConfig {
157+
return RetryConfig{
155158
delay: DefaultSDKv2HelperRetryCompatibleDelay(),
156159
gracePeriod: 30 * time.Second,
157160
timer: &timerImpl{},
158161
}
159162
}
160163

161-
// RetryWithTimeout holds state for managing retry loops with a timeout.
162-
type RetryWithTimeout struct {
164+
// RetryLoop holds state for managing retry loops with a timeout.
165+
type RetryLoop struct {
163166
attempt uint
164-
config Config
167+
config RetryConfig
165168
deadline deadline
166169
timedOut bool
167170
}
168171

169-
// BeginWithOptions returns a new retry loop configured with the provided options.
170-
func BeginWithOptions(timeout time.Duration, opts ...Option) *RetryWithTimeout {
171-
config := defaultConfig()
172+
// NewRetryLoopWithOptions returns a new retry loop configured with the provided options.
173+
func NewRetryLoopWithOptions(timeout time.Duration, opts ...Option) *RetryLoop {
174+
config := defaultRetryConfig()
172175
for _, opt := range opts {
173176
opt(&config)
174177
}
175178

176-
return &RetryWithTimeout{
179+
return &RetryLoop{
177180
config: config,
178-
deadline: NewDeadline(timeout),
181+
deadline: NewDeadline(timeout + config.gracePeriod),
179182
}
180183
}
181184

182-
// Begin returns a new retry loop configured with the default options.
183-
func Begin(timeout time.Duration) *RetryWithTimeout {
184-
return BeginWithOptions(timeout)
185+
// NewRetryLoop returns a new retry loop configured with the default options.
186+
func NewRetryLoop(timeout time.Duration) *RetryLoop {
187+
return NewRetryLoopWithOptions(timeout)
185188
}
186189

187190
// Continue sleeps between retry attempts.
188191
// It returns false if the timeout has been exceeded.
189192
// The deadline is not checked on the first call to Continue.
190-
func (r *RetryWithTimeout) Continue(ctx context.Context) bool {
193+
func (r *RetryLoop) Continue(ctx context.Context) bool {
191194
if r.attempt != 0 && r.deadline.Remaining() == 0 {
192-
if r.config.gracePeriod == 0 {
193-
r.timedOut = true
194-
return false
195-
}
195+
r.timedOut = true
196196

197-
r.deadline = NewDeadline(r.config.gracePeriod)
198-
r.config.gracePeriod = 0
197+
return false
199198
}
200199

201200
r.sleep(ctx, r.config.delay(r.attempt))
@@ -204,18 +203,18 @@ func (r *RetryWithTimeout) Continue(ctx context.Context) bool {
204203
return true
205204
}
206205

207-
// Reset resets a RetryWithTimeout to its initial state.
208-
func (r *RetryWithTimeout) Reset() {
206+
// Reset resets a RetryLoop to its initial state.
207+
func (r *RetryLoop) Reset() {
209208
r.attempt = 0
210209
}
211210

212211
// TimedOut return whether the retry timed out.
213-
func (r *RetryWithTimeout) TimedOut() bool {
212+
func (r *RetryLoop) TimedOut() bool {
214213
return r.timedOut
215214
}
216215

217-
// Sleeps for the specified duration or until context is done, whichever occurs first.
218-
func (r *RetryWithTimeout) sleep(ctx context.Context, d time.Duration) {
216+
// sleep sleeps for the specified duration or until the context is canceled, whichever occurs first.
217+
func (r *RetryLoop) sleep(ctx context.Context, d time.Duration) {
219218
if d == 0 {
220219
return
221220
}

internal/retry2/retry_test.go renamed to internal/backoff/backoff_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) HashiCorp, Inc.
22
// SPDX-License-Identifier: MPL-2.0
33

4-
package retry2
4+
package backoff
55

66
import (
77
"context"
@@ -85,7 +85,7 @@ func TestRetryWithTimeoutDefaultGracePeriod(t *testing.T) {
8585
ctx := context.Background()
8686

8787
var n int
88-
for r := BeginWithOptions(1*time.Minute, WithDelay(FixedDelay(1*time.Second))); r.Continue(ctx); {
88+
for r := NewRetryLoopWithOptions(1*time.Minute, WithDelay(FixedDelay(1*time.Second))); r.Continue(ctx); {
8989
time.Sleep(35 * time.Second)
9090
n++
9191
}
@@ -102,7 +102,7 @@ func TestRetryWithTimeoutNoGracePeriod(t *testing.T) {
102102
ctx := context.Background()
103103

104104
var n int
105-
for r := BeginWithOptions(1*time.Minute, WithDelay(FixedDelay(1*time.Second)), WithGracePeriod(0)); r.Continue(ctx); {
105+
for r := NewRetryLoopWithOptions(1*time.Minute, WithDelay(FixedDelay(1*time.Second)), WithGracePeriod(0)); r.Continue(ctx); {
106106
time.Sleep(35 * time.Second)
107107
n++
108108
}

internal/retry2/deadline.go renamed to internal/backoff/deadline.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) HashiCorp, Inc.
22
// SPDX-License-Identifier: MPL-2.0
33

4-
package retry2
4+
package backoff
55

66
import (
77
"time"

internal/service/ec2/ec2_instance.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ import (
3131
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
3232
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
3333
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
34+
"github.com/hashicorp/terraform-provider-aws/internal/backoff"
3435
"github.com/hashicorp/terraform-provider-aws/internal/conns"
3536
"github.com/hashicorp/terraform-provider-aws/internal/create"
3637
"github.com/hashicorp/terraform-provider-aws/internal/enum"
3738
"github.com/hashicorp/terraform-provider-aws/internal/errs"
3839
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
3940
"github.com/hashicorp/terraform-provider-aws/internal/flex"
40-
"github.com/hashicorp/terraform-provider-aws/internal/retry2"
4141
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
4242
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
4343
itypes "github.com/hashicorp/terraform-provider-aws/internal/types"
@@ -1051,7 +1051,7 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, meta an
10511051
}
10521052

10531053
var output *ec2.RunInstancesOutput
1054-
for r := retry2.Begin(iamPropagationTimeout); r.Continue(ctx); {
1054+
for r := backoff.NewRetryLoop(iamPropagationTimeout); r.Continue(ctx); {
10551055
output, err = conn.RunInstances(ctx, &input)
10561056

10571057
// IAM instance profiles can take ~10 seconds to propagate in AWS:

0 commit comments

Comments
 (0)