@@ -77,21 +77,28 @@ type Engine struct {
77
77
// section when starting a new section.
78
78
Quiet bool
79
79
80
- // RetryInterval for retrying commands marked with '*'. If zero, then
81
- // the default retry interval is used.
80
+ // RetryInterval is the minimal interval for retrying commands marked with '*'.
81
+ // If zero, then the default retry interval is used.
82
82
RetryInterval time.Duration
83
+
84
+ // MaxRetryInterval is the maximum time to wait before retrying.
85
+ MaxRetryInterval time.Duration
83
86
}
84
87
85
88
// NewEngine returns an Engine configured with a basic set of commands and conditions.
86
89
func NewEngine () * Engine {
87
90
return & Engine {
88
- Cmds : DefaultCmds (),
89
- Conds : DefaultConds (),
90
- RetryInterval : defaultRetryInterval ,
91
+ Cmds : DefaultCmds (),
92
+ Conds : DefaultConds (),
93
+ RetryInterval : defaultRetryInterval ,
94
+ MaxRetryInterval : defaultMaxRetryInterval ,
91
95
}
92
96
}
93
97
94
- const defaultRetryInterval = 100 * time .Millisecond
98
+ const (
99
+ defaultRetryInterval = 100 * time .Millisecond
100
+ defaultMaxRetryInterval = 500 * time .Millisecond
101
+ )
95
102
96
103
// A Cmd is a command that is available to a script.
97
104
type Cmd interface {
@@ -331,14 +338,16 @@ func (e *Engine) Execute(s *State, file string, script *bufio.Reader, log io.Wri
331
338
if cmd .want == successRetryOnFailure || cmd .want == failureRetryOnSuccess {
332
339
// Command wants retries. Retry the whole section
333
340
numRetries := 0
341
+ backoff := exponentialBackoff {max : e .MaxRetryInterval , interval : e .RetryInterval }
334
342
for err != nil {
335
343
s .FlushLog ()
344
+ retryDuration := backoff .get ()
345
+ s .Logf ("(command %q failed, retrying in %s...)\n " , line , retryDuration )
336
346
select {
337
347
case <- s .Context ().Done ():
338
348
return lineErr (s .Context ().Err ())
339
- case <- time .After (retryInterval ):
349
+ case <- time .After (retryDuration ):
340
350
}
341
- s .Logf ("(command %q failed, retrying...)\n " , line )
342
351
numRetries ++
343
352
for _ , cmd := range sectionCmds {
344
353
impl := e .Cmds [cmd .name ]
@@ -997,3 +1006,14 @@ func (e *Engine) ListConds(w io.Writer, s *State, tags ...string) error {
997
1006
998
1007
return nil
999
1008
}
1009
+
1010
+ type exponentialBackoff struct {
1011
+ max time.Duration
1012
+ interval time.Duration
1013
+ }
1014
+
1015
+ func (eb * exponentialBackoff ) get () time.Duration {
1016
+ d := eb .interval
1017
+ eb .interval = min (eb .interval * 2 , eb .max )
1018
+ return d
1019
+ }
0 commit comments