forked from benthosdev/benthos
/
config_backoff.go
140 lines (127 loc) · 5.76 KB
/
config_backoff.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package service
import (
"github.com/cenkalti/backoff/v4"
)
// NewBackOffField defines a new object type config field that describes an
// exponential back off policy, often used for timing retry attempts. It is then
// possible to extract a *backoff.ExponentialBackOff from the resulting parsed
// config with the method FieldBackOff.
//
// It is possible to configure a back off policy that has no upper bound (no
// maximum elapsed time set). In cases where this would be problematic the field
// allowUnbounded should be set `false` in order to add linting rules that
// ensure an upper bound is set.
//
// The defaults struct is optional, and if provided will be used to establish
// default values for time interval fields. Otherwise the chosen defaults result
// in one minute of retry attempts, starting at 500ms intervals.
func NewBackOffField(name string, allowUnbounded bool, defaults *backoff.ExponentialBackOff) *ConfigField {
var (
initDefault = "500ms"
maxDefault = "10s"
maxElapsedDefault = "1m"
)
if defaults != nil {
initDefault = defaults.InitialInterval.String()
maxDefault = defaults.MaxInterval.String()
maxElapsedDefault = defaults.MaxElapsedTime.String()
}
maxElapsedTime := NewDurationField("max_elapsed_time").
Description("The maximum overall period of time to spend on retry attempts before the request is aborted.").
Default(maxElapsedDefault).Example("1m").Example("1h")
if allowUnbounded {
maxElapsedTime.field.Description += " Setting this value to a zeroed duration (such as `0s`) will result in unbounded retries."
}
// TODO: Add linting rule to ensure we aren't unbounded if necessary.
return NewObjectField(name,
NewDurationField("initial_interval").
Description("The initial period to wait between retry attempts.").
Default(initDefault).Example("50ms").Example("1s"),
NewDurationField("max_interval").
Description("The maximum period to wait between retry attempts").
Default(maxDefault).Example("5s").Example("1m"),
maxElapsedTime,
).Description("Determine time intervals and cut offs for retry attempts.")
}
// FieldBackOff accesses a field from a parsed config that was defined with
// NewBackoffField and returns a *backoff.ExponentialBackOff, or an error if the
// configuration was invalid.
func (p *ParsedConfig) FieldBackOff(path ...string) (*backoff.ExponentialBackOff, error) {
b := backoff.NewExponentialBackOff()
var err error
if b.InitialInterval, err = p.FieldDuration(append(path, "initial_interval")...); err != nil {
return nil, err
}
if b.MaxInterval, err = p.FieldDuration(append(path, "max_interval")...); err != nil {
return nil, err
}
if b.MaxElapsedTime, err = p.FieldDuration(append(path, "max_elapsed_time")...); err != nil {
return nil, err
}
return b, nil
}
// NewBackOffToggledField defines a new object type config field that describes
// an exponential back off policy, often used for timing retry attempts. It is
// then possible to extract a *backoff.ExponentialBackOff from the resulting
// parsed config with the method FieldBackOff. This Toggled variant includes a
// field `enabled` that is `false` by default.
//
// It is possible to configure a back off policy that has no upper bound (no
// maximum elapsed time set). In cases where this would be problematic the field
// allowUnbounded should be set `false` in order to add linting rules that
// ensure an upper bound is set.
//
// The defaults struct is optional, and if provided will be used to establish
// default values for time interval fields. Otherwise the chosen defaults result
// in one minute of retry attempts, starting at 500ms intervals.
func NewBackOffToggledField(name string, allowUnbounded bool, defaults *backoff.ExponentialBackOff) *ConfigField {
var (
initDefault = "500ms"
maxDefault = "10s"
maxElapsedDefault = "1m"
)
if defaults != nil {
initDefault = defaults.InitialInterval.String()
maxDefault = defaults.MaxInterval.String()
maxElapsedDefault = defaults.MaxElapsedTime.String()
}
maxElapsedTime := NewDurationField("max_elapsed_time").
Description("The maximum overall period of time to spend on retry attempts before the request is aborted.").
Default(maxElapsedDefault).Example("1m").Example("1h")
if allowUnbounded {
maxElapsedTime.field.Description += " Setting this value to a zeroed duration (such as `0s`) will result in unbounded retries."
}
// TODO: Add linting rule to ensure we aren't unbounded if necessary.
return NewObjectField(name,
NewBoolField("enabled").
Description("Whether retries should be enabled.").
Default(false),
NewDurationField("initial_interval").
Description("The initial period to wait between retry attempts.").
Default(initDefault).Example("50ms").Example("1s"),
NewDurationField("max_interval").
Description("The maximum period to wait between retry attempts").
Default(maxDefault).Example("5s").Example("1m"),
maxElapsedTime,
).Description("Determine time intervals and cut offs for retry attempts.")
}
// FieldBackOffToggled accesses a field from a parsed config that was defined
// with NewBackOffField and returns a *backoff.ExponentialBackOff and a boolean
// flag indicating whether retries are explicitly enabled, or an error if the
// configuration was invalid.
func (p *ParsedConfig) FieldBackOffToggled(path ...string) (boff *backoff.ExponentialBackOff, enabled bool, err error) {
boff = backoff.NewExponentialBackOff()
if enabled, err = p.FieldBool(append(path, "enabled")...); err != nil {
return
}
if boff.InitialInterval, err = p.FieldDuration(append(path, "initial_interval")...); err != nil {
return
}
if boff.MaxInterval, err = p.FieldDuration(append(path, "max_interval")...); err != nil {
return
}
if boff.MaxElapsedTime, err = p.FieldDuration(append(path, "max_elapsed_time")...); err != nil {
return
}
return
}