This repository has been archived by the owner on Jul 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
/
backend.go
111 lines (89 loc) · 2.01 KB
/
backend.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
package balancer
import (
"strings"
"sync/atomic"
backendpb "github.com/bsm/grpclb/grpclb_backend_v1"
balancerpb "github.com/bsm/grpclb/grpclb_balancer_v1"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
)
type backend struct {
cc *grpc.ClientConn
cln backendpb.LoadReportClient
target string
address string
score int64
maxFailures int
failures int
}
func newBackend(target, address string, maxFailures int) (*backend, error) {
cc, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
return nil, err
}
b := &backend{
cc: cc,
cln: backendpb.NewLoadReportClient(cc),
target: target,
address: address,
maxFailures: maxFailures,
}
if err := b.UpdateScore(); err != nil {
b.Close()
return nil, err
}
return b, nil
}
func (b *backend) Server() *balancerpb.Server {
return &balancerpb.Server{
Address: b.address,
Score: b.Score(),
}
}
func (b *backend) Score() int64 {
return atomic.LoadInt64(&b.score)
}
func (b *backend) UpdateScore() error {
resp, err := b.cln.Load(context.Background(), &backendpb.LoadRequest{})
if err != nil {
return b.handleError(err)
}
b.failures = 0 // clear failures on success
atomic.StoreInt64(&b.score, resp.Score)
return nil
}
func (b *backend) Close() error {
return b.cc.Close()
}
func (b *backend) handleError(err error) error {
switch err {
case grpc.ErrClientConnClosing:
return err
}
code := grpc.Code(err)
if code == codes.Unimplemented {
return nil
}
b.failures++
grpclog.Printf("error retrieving load score for %s from %s (failures: %d): %s", b.target, b.address, b.failures, err)
// recoverable errors:
switch code {
case codes.Canceled:
if strings.Contains(err.Error(), "closing") {
return err
}
fallthrough
case codes.DeadlineExceeded,
codes.ResourceExhausted,
codes.FailedPrecondition,
codes.Aborted:
if b.maxFailures > 0 && b.failures >= b.maxFailures {
return err
}
return nil
}
// fatal errors:
return err
}