14 | 14 |
// error message if desired. The error message may be nil, but a true/false
|
15 | 15 |
// is always expected. In all cases if the error message is supplied, the
|
16 | 16 |
// current error will be replaced.
|
17 | |
type callback func(int, string) (bool, *string)
|
|
17 |
type Callback func(int, string) (bool, *string)
|
18 | 18 |
|
19 | 19 |
// Retry wraps a service load balancer and returns an endpoint oriented load
|
20 | 20 |
// balancer for the specified service method.
|
|
22 | 22 |
// balancer. Requests that return errors will be retried until they succeed,
|
23 | 23 |
// up to max times, or until the timeout is elapsed, whichever comes first.
|
24 | 24 |
func Retry(max int, timeout time.Duration, b Balancer) endpoint.Endpoint {
|
25 | |
if b == nil {
|
26 | |
panic("nil Balancer")
|
27 | |
}
|
28 | |
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
29 | |
var (
|
30 | |
newctx, cancel = context.WithTimeout(ctx, timeout)
|
31 | |
responses = make(chan interface{}, 1)
|
32 | |
errs = make(chan error, 1)
|
33 | |
a = []string{}
|
34 | |
)
|
35 | |
defer cancel()
|
36 | |
for i := 1; i <= max; i++ {
|
37 | |
go func() {
|
38 | |
e, err := b.Endpoint()
|
39 | |
if err != nil {
|
40 | |
errs <- err
|
41 | |
return
|
42 | |
}
|
43 | |
response, err := e(newctx, request)
|
44 | |
if err != nil {
|
45 | |
errs <- err
|
46 | |
return
|
47 | |
}
|
48 | |
responses <- response
|
49 | |
}()
|
50 | |
|
51 | |
select {
|
52 | |
case <-newctx.Done():
|
53 | |
return nil, newctx.Err()
|
54 | |
case response := <-responses:
|
55 | |
return response, nil
|
56 | |
case err := <-errs:
|
57 | |
a = append(a, err.Error())
|
58 | |
continue
|
59 | |
}
|
60 | |
}
|
61 | |
return nil, fmt.Errorf("retry attempts exceeded (%s)", strings.Join(a, "; "))
|
62 | |
}
|
|
25 |
return RetryWithCallback(max, timeout, b, func(c int, s string) (bool, *string) { return true, nil })
|
63 | 26 |
}
|
64 | 27 |
|
65 | |
func RetryWithCallback(max int, timeout time.Duration, b Balancer, cb callback) endpoint.Endpoint {
|
|
28 |
func RetryWithCallback(max int, timeout time.Duration, b Balancer, cb Callback) endpoint.Endpoint {
|
66 | 29 |
if cb == nil {
|
67 | |
panic("nil callback")
|
|
30 |
panic("nil Callback")
|
68 | 31 |
}
|
69 | 32 |
if b == nil {
|
70 | 33 |
panic("nil Balancer")
|