Skip to content

Commit 10de202

Browse files
authored
Sets default activity maximum retry interval to be 100x minimum retry interval (#630)
Fixes situation where user sets an initial retry interval that is greater than 100 seconds, but doesn't explicitly set the maximum retry interval, which will lead to a validation failure when they try to start an activity.
1 parent 1f880f6 commit 10de202

File tree

8 files changed

+95
-60
lines changed

8 files changed

+95
-60
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package common
2+
3+
// DefaultActivityRetrySettings indicates what the "default" activity retry settings
4+
// are of it is not specified on an Activity
5+
type DefaultActivityRetrySettings struct {
6+
InitialIntervalInSeconds int32
7+
MaximumIntervalCoefficient float64
8+
BackoffCoefficient float64
9+
MaximumAttempts int32
10+
}

common/util.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -368,32 +368,32 @@ func SortInt64Slice(slice []int64) {
368368
}
369369

370370
// EnsureRetryPolicyDefaults ensures the policy subfields, if not explicitly set, are set to the specified defaults
371-
func EnsureRetryPolicyDefaults(originalPolicy *commonpb.RetryPolicy, defaultPolicy *commonpb.RetryPolicy) *commonpb.RetryPolicy {
372-
if originalPolicy == nil {
373-
return defaultPolicy
374-
}
375-
376-
merged := &commonpb.RetryPolicy{
377-
BackoffCoefficient: originalPolicy.GetBackoffCoefficient(),
378-
InitialIntervalInSeconds: originalPolicy.GetInitialIntervalInSeconds(),
379-
MaximumIntervalInSeconds: originalPolicy.GetMaximumIntervalInSeconds(),
380-
MaximumAttempts: originalPolicy.GetMaximumAttempts(),
371+
func EnsureRetryPolicyDefaults(originalPolicy *commonpb.RetryPolicy, defaultSettings DefaultActivityRetrySettings) *commonpb.RetryPolicy {
372+
var merged *commonpb.RetryPolicy = &commonpb.RetryPolicy{}
373+
374+
if originalPolicy != nil {
375+
merged = &commonpb.RetryPolicy{
376+
BackoffCoefficient: originalPolicy.GetBackoffCoefficient(),
377+
InitialIntervalInSeconds: originalPolicy.GetInitialIntervalInSeconds(),
378+
MaximumIntervalInSeconds: originalPolicy.GetMaximumIntervalInSeconds(),
379+
MaximumAttempts: originalPolicy.GetMaximumAttempts(),
380+
}
381381
}
382382

383383
if merged.GetMaximumAttempts() == 0 {
384-
merged.MaximumAttempts = defaultPolicy.GetMaximumAttempts()
384+
merged.MaximumAttempts = int32(defaultSettings.MaximumAttempts)
385385
}
386386

387387
if merged.GetInitialIntervalInSeconds() == 0 {
388-
merged.InitialIntervalInSeconds = defaultPolicy.GetInitialIntervalInSeconds()
388+
merged.InitialIntervalInSeconds = int32(defaultSettings.InitialIntervalInSeconds)
389389
}
390390

391391
if merged.GetMaximumIntervalInSeconds() == 0 {
392-
merged.MaximumIntervalInSeconds = defaultPolicy.GetMaximumIntervalInSeconds()
392+
merged.MaximumIntervalInSeconds = int32(defaultSettings.MaximumIntervalCoefficient * float64(merged.GetInitialIntervalInSeconds()))
393393
}
394394

395395
if merged.GetBackoffCoefficient() == 0 {
396-
merged.BackoffCoefficient = defaultPolicy.GetBackoffCoefficient()
396+
merged.BackoffCoefficient = defaultSettings.BackoffCoefficient
397397
}
398398

399399
return merged

common/util_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,17 @@ func TestValidateRetryPolicy(t *testing.T) {
8989
}
9090

9191
func TestEnsureRetryPolicyDefaults(t *testing.T) {
92+
defaultActivityRetrySettings := DefaultActivityRetrySettings{
93+
InitialIntervalInSeconds: 1,
94+
MaximumIntervalCoefficient: 100,
95+
BackoffCoefficient: 2.0,
96+
MaximumAttempts: 120,
97+
}
98+
9299
defaultRetryPolicy := &commonpb.RetryPolicy{
93100
InitialIntervalInSeconds: 1,
94101
MaximumIntervalInSeconds: 100,
95-
BackoffCoefficient: 2,
102+
BackoffCoefficient: 2.0,
96103
MaximumAttempts: 120,
97104
}
98105

@@ -118,7 +125,7 @@ func TestEnsureRetryPolicyDefaults(t *testing.T) {
118125
},
119126
want: &commonpb.RetryPolicy{
120127
InitialIntervalInSeconds: 2,
121-
MaximumIntervalInSeconds: 100,
128+
MaximumIntervalInSeconds: 200,
122129
BackoffCoefficient: 2,
123130
MaximumAttempts: 120,
124131
},
@@ -163,7 +170,7 @@ func TestEnsureRetryPolicyDefaults(t *testing.T) {
163170

164171
for _, tt := range testCases {
165172
t.Run(tt.name, func(t *testing.T) {
166-
got := EnsureRetryPolicyDefaults(tt.input, defaultRetryPolicy)
173+
got := EnsureRetryPolicyDefaults(tt.input, defaultActivityRetrySettings)
167174
assert.Equal(t, tt.want, got)
168175
})
169176
}

config/dynamicconfig/development.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ system.advancedVisibilityWritingMode:
2424
constraints: {}
2525
history.defaultActivityRetryPolicy:
2626
- value:
27-
InitialRetryIntervalInSeconds: 1
28-
MaximumRetryIntervalInSeconds: 120
29-
ExponentialBackoffCoefficient: 2.0
27+
InitialIntervalInSeconds: 1
28+
MaximumIntervalCoefficient: 100.0
29+
BackoffCoefficient: 2.0
3030
MaximumAttempts: 0

service/history/commandChecker.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ import (
5151

5252
type (
5353
commandAttrValidator struct {
54-
namespaceCache cache.NamespaceCache
55-
config *Config
56-
maxIDLengthLimit int
57-
searchAttributesValidator *validator.SearchAttributesValidator
58-
defaultActivityRetryPolicy *commonpb.RetryPolicy
54+
namespaceCache cache.NamespaceCache
55+
config *Config
56+
maxIDLengthLimit int
57+
searchAttributesValidator *validator.SearchAttributesValidator
58+
defaultActivityRetrySettings common.DefaultActivityRetrySettings
5959
}
6060

6161
workflowSizeChecker struct {
@@ -96,7 +96,7 @@ func newCommandAttrValidator(
9696
config.SearchAttributesSizeOfValueLimit,
9797
config.SearchAttributesTotalSizeLimit,
9898
),
99-
defaultActivityRetryPolicy: fromConfigToActivityRetryPolicy(config.DefaultActivityRetryPolicy()),
99+
defaultActivityRetrySettings: fromConfigToDefaultActivityRetrySettings(config.DefaultActivityRetryPolicy()),
100100
}
101101
}
102102

@@ -652,12 +652,7 @@ func (v *commandAttrValidator) validateTaskQueue(
652652
}
653653

654654
func (v *commandAttrValidator) validateActivityRetryPolicy(attributes *commandpb.ScheduleActivityTaskCommandAttributes) error {
655-
if attributes.RetryPolicy == nil {
656-
attributes.RetryPolicy = v.defaultActivityRetryPolicy
657-
return nil
658-
}
659-
660-
attributes.RetryPolicy = common.EnsureRetryPolicyDefaults(attributes.RetryPolicy, v.defaultActivityRetryPolicy)
655+
attributes.RetryPolicy = common.EnsureRetryPolicyDefaults(attributes.RetryPolicy, v.defaultActivityRetrySettings)
661656
return common.ValidateRetryPolicy(attributes.RetryPolicy)
662657
}
663658

service/history/commandChecker_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ func (s *commandAttrValidatorSuite) TestValidateActivityRetryPolicy() {
587587
},
588588
},
589589
{
590-
name: "partial override set policy",
590+
name: "partial override of fields",
591591
input: &commonpb.RetryPolicy{
592592
InitialIntervalInSeconds: 0,
593593
BackoffCoefficient: 1.2,
@@ -601,6 +601,19 @@ func (s *commandAttrValidatorSuite) TestValidateActivityRetryPolicy() {
601601
MaximumAttempts: 7,
602602
},
603603
},
604+
{
605+
name: "set expected max interval if only init interval set",
606+
input: &commonpb.RetryPolicy{
607+
InitialIntervalInSeconds: 3,
608+
MaximumIntervalInSeconds: 0,
609+
},
610+
want: &commonpb.RetryPolicy{
611+
InitialIntervalInSeconds: 3,
612+
BackoffCoefficient: 2,
613+
MaximumIntervalInSeconds: 300,
614+
MaximumAttempts: 0,
615+
},
616+
},
604617
{
605618
name: "override all defaults",
606619
input: &commonpb.RetryPolicy{

service/history/retry.go

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@ import (
2929
"math"
3030
"time"
3131

32-
commonpb "go.temporal.io/api/common/v1"
3332
enumspb "go.temporal.io/api/enums/v1"
3433
failurepb "go.temporal.io/api/failure/v1"
3534

3635
"go.temporal.io/server/common"
3736
"go.temporal.io/server/common/backoff"
3837
)
3938

39+
const defaultInitialIntervalInSeconds = 1
40+
const defaultMaximumIntervalCoefficient = 100.0
41+
const defaultBackoffCoefficient = 2.0
42+
const defaultMaximumAttempts = 0
43+
4044
func getBackoffInterval(
4145
now time.Time,
4246
expirationTime time.Time,
@@ -133,43 +137,49 @@ func isRetryable(failure *failurepb.Failure, nonRetryableTypes []string) bool {
133137

134138
func getDefaultActivityRetryPolicyConfigOptions() map[string]interface{} {
135139
return map[string]interface{}{
136-
"InitialRetryIntervalInSeconds": 1,
137-
"MaximumRetryIntervalInSeconds": 100,
138-
"ExponentialBackoffCoefficient": 2.0,
139-
"MaximumAttempts": 0,
140+
"InitialIntervalInSeconds": 1,
141+
"MaximumIntervalInSeconds": 100,
142+
"BackoffCoefficient": 2.0,
143+
"MaximumAttempts": 0,
140144
}
141145
}
142146

143-
func fromConfigToActivityRetryPolicy(options map[string]interface{}) *commonpb.RetryPolicy {
144-
retryPolicy := &commonpb.RetryPolicy{}
145-
initialRetryInterval, ok := options["InitialRetryIntervalInSeconds"]
147+
func fromConfigToDefaultActivityRetrySettings(options map[string]interface{}) common.DefaultActivityRetrySettings {
148+
defaultSettings := common.DefaultActivityRetrySettings{
149+
InitialIntervalInSeconds: defaultInitialIntervalInSeconds,
150+
MaximumIntervalCoefficient: defaultMaximumIntervalCoefficient,
151+
BackoffCoefficient: defaultBackoffCoefficient,
152+
MaximumAttempts: defaultMaximumAttempts,
153+
}
154+
155+
initialIntervalInSeconds, ok := options["InitialIntervalInSeconds"]
146156
if ok {
147-
retryPolicy.InitialIntervalInSeconds = int32(initialRetryInterval.(int))
157+
defaultSettings.InitialIntervalInSeconds = int32(initialIntervalInSeconds.(int))
148158
}
149159

150-
maxRetryInterval, ok := options["MaximumRetryIntervalInSeconds"]
160+
maximumIntervalCoefficient, ok := options["MaximumIntervalCoefficient"]
151161
if ok {
152-
retryPolicy.MaximumIntervalInSeconds = int32(maxRetryInterval.(int))
162+
defaultSettings.MaximumIntervalCoefficient = maximumIntervalCoefficient.(float64)
153163
}
154164

155-
exponentialBackoffCoefficient, ok := options["ExponentialBackoffCoefficient"]
165+
backoffCoefficient, ok := options["BackoffCoefficient"]
156166
if ok {
157-
retryPolicy.BackoffCoefficient = exponentialBackoffCoefficient.(float64)
167+
defaultSettings.BackoffCoefficient = backoffCoefficient.(float64)
158168
}
159169

160170
maximumAttempts, ok := options["MaximumAttempts"]
161171
if ok {
162-
retryPolicy.MaximumAttempts = int32(maximumAttempts.(int))
172+
defaultSettings.MaximumAttempts = int32(maximumAttempts.(int))
163173
}
164174

165-
err := common.ValidateRetryPolicy(retryPolicy)
175+
err := common.ValidateRetryPolicy(common.EnsureRetryPolicyDefaults(nil, defaultSettings))
166176
if err != nil {
167177
panic(
168178
fmt.Sprintf(
169-
"Bad Default Activity Retry Policy defined: %+v failed validation %v",
170-
retryPolicy,
179+
"Bad Default Activity Retry Settings defined: %+v failed validation %v",
180+
defaultSettings,
171181
err))
172182
}
173183

174-
return retryPolicy
184+
return defaultSettings
175185
}

service/history/retry_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -398,15 +398,15 @@ func Test_NextRetry(t *testing.T) {
398398

399399
func Test_FromConfigToActivityRetryPolicy(t *testing.T) {
400400
options := map[string]interface{}{
401-
"InitialRetryIntervalInSeconds": 2,
402-
"MaximumRetryIntervalInSeconds": 200,
403-
"ExponentialBackoffCoefficient": 4.0,
404-
"MaximumAttempts": 5,
401+
"InitialIntervalInSeconds": 2,
402+
"MaximumIntervalCoefficient": 100.0,
403+
"BackoffCoefficient": 4.0,
404+
"MaximumAttempts": 5,
405405
}
406406

407-
policy := fromConfigToActivityRetryPolicy(options)
408-
assert.Equal(t, int32(2), policy.GetInitialIntervalInSeconds())
409-
assert.Equal(t, int32(200), policy.GetMaximumIntervalInSeconds())
410-
assert.Equal(t, 4.0, policy.GetBackoffCoefficient())
411-
assert.Equal(t, int32(5), policy.GetMaximumAttempts())
407+
defaultSettings := fromConfigToDefaultActivityRetrySettings(options)
408+
assert.Equal(t, int32(2), defaultSettings.InitialIntervalInSeconds)
409+
assert.Equal(t, 100.0, defaultSettings.MaximumIntervalCoefficient)
410+
assert.Equal(t, 4.0, defaultSettings.BackoffCoefficient)
411+
assert.Equal(t, int32(5), defaultSettings.MaximumAttempts)
412412
}

0 commit comments

Comments
 (0)