OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / cenkalti / backoff / retry.go
1 package backoff
2
3 import "time"
4
5 // An Operation is executing by Retry() or RetryNotify().
6 // The operation will be retried using a backoff policy if it returns an error.
7 type Operation func() error
8
9 // Notify is a notify-on-error function. It receives an operation error and
10 // backoff delay if the operation failed (with an error).
11 //
12 // NOTE that if the backoff policy stated to stop retrying,
13 // the notify function isn't called.
14 type Notify func(error, time.Duration)
15
16 // Retry the operation o until it does not return error or BackOff stops.
17 // o is guaranteed to be run at least once.
18 //
19 // If o returns a *PermanentError, the operation is not retried, and the
20 // wrapped error is returned.
21 //
22 // Retry sleeps the goroutine for the duration returned by BackOff after a
23 // failed operation returns.
24 func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) }
25
26 // RetryNotify calls notify function with the error and wait duration
27 // for each failed attempt before sleep.
28 func RetryNotify(operation Operation, b BackOff, notify Notify) error {
29         var err error
30         var next time.Duration
31         var t *time.Timer
32
33         cb := ensureContext(b)
34
35         b.Reset()
36         for {
37                 if err = operation(); err == nil {
38                         return nil
39                 }
40
41                 if permanent, ok := err.(*PermanentError); ok {
42                         return permanent.Err
43                 }
44
45                 if next = cb.NextBackOff(); next == Stop {
46                         return err
47                 }
48
49                 if notify != nil {
50                         notify(err, next)
51                 }
52
53                 if t == nil {
54                         t = time.NewTimer(next)
55                         defer t.Stop()
56                 } else {
57                         t.Reset(next)
58                 }
59
60                 select {
61                 case <-cb.Context().Done():
62                         return err
63                 case <-t.C:
64                 }
65         }
66 }
67
68 // PermanentError signals that the operation should not be retried.
69 type PermanentError struct {
70         Err error
71 }
72
73 func (e *PermanentError) Error() string {
74         return e.Err.Error()
75 }
76
77 // Permanent wraps the given err in a *PermanentError.
78 func Permanent(err error) *PermanentError {
79         return &PermanentError{
80                 Err: err,
81         }
82 }