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