50 | 50 |
close(p.quit)
|
51 | 51 |
}
|
52 | 52 |
|
53 | |
func (p *Publisher) loop(endpoints []endpoint.Endpoint, md5 string) {
|
|
53 |
func (p *Publisher) loop(m map[string]endpointCloser, md5 string) {
|
54 | 54 |
t := newTicker(p.ttl)
|
55 | 55 |
defer t.Stop()
|
56 | 56 |
for {
|
57 | 57 |
select {
|
58 | |
case p.endpoints <- endpoints:
|
|
58 |
case p.endpoints <- flatten(m):
|
59 | 59 |
|
60 | 60 |
case <-t.C:
|
61 | 61 |
// TODO should we do this out-of-band?
|
62 | 62 |
addrs, newmd5, err := resolve(p.name)
|
63 | 63 |
if err != nil {
|
64 | 64 |
p.logger.Log("name", p.name, "err", err)
|
65 | |
continue // don't replace good endpoints with bad ones
|
|
65 |
continue // don't replace probably-good endpoints with bad ones
|
66 | 66 |
}
|
67 | 67 |
if newmd5 == md5 {
|
68 | |
continue // no change
|
|
68 |
continue // optimization: no change
|
69 | 69 |
}
|
70 | |
endpoints = makeEndpoints(addrs, p.factory, p.logger)
|
|
70 |
m = migrate(m, makeEndpoints(addrs, p.factory, p.logger))
|
71 | 71 |
md5 = newmd5
|
72 | 72 |
|
73 | 73 |
case <-p.quit:
|
|
96 | 96 |
if err != nil {
|
97 | 97 |
return addrs, "", err
|
98 | 98 |
}
|
99 | |
hostports := make([]string, len(addrs))
|
|
99 |
instances := make([]string, len(addrs))
|
100 | 100 |
for i, addr := range addrs {
|
101 | |
hostports[i] = fmt.Sprintf("%s:%d", addr.Target, addr.Port)
|
|
101 |
instances[i] = addr2instance(addr)
|
102 | 102 |
}
|
103 | |
sort.Sort(sort.StringSlice(hostports))
|
|
103 |
sort.Sort(sort.StringSlice(instances))
|
104 | 104 |
h := md5.New()
|
105 | |
for _, hostport := range hostports {
|
106 | |
fmt.Fprintf(h, hostport)
|
|
105 |
for _, instance := range instances {
|
|
106 |
fmt.Fprintf(h, instance)
|
107 | 107 |
}
|
108 | 108 |
return addrs, fmt.Sprintf("%x", h.Sum(nil)), nil
|
109 | 109 |
}
|
110 | 110 |
|
111 | |
func makeEndpoints(addrs []*net.SRV, f loadbalancer.Factory, logger log.Logger) []endpoint.Endpoint {
|
112 | |
endpoints := make([]endpoint.Endpoint, 0, len(addrs))
|
|
111 |
func makeEndpoints(addrs []*net.SRV, f loadbalancer.Factory, logger log.Logger) map[string]endpointCloser {
|
|
112 |
m := make(map[string]endpointCloser, len(addrs))
|
113 | 113 |
for _, addr := range addrs {
|
114 | |
endpoint, err := f(addr2instance(addr))
|
|
114 |
instance := addr2instance(addr)
|
|
115 |
endpoint, closer, err := f(instance)
|
115 | 116 |
if err != nil {
|
116 | 117 |
logger.Log("instance", addr2instance(addr), "err", err)
|
117 | 118 |
continue
|
118 | 119 |
}
|
119 | |
endpoints = append(endpoints, endpoint)
|
|
120 |
m[instance] = endpointCloser{endpoint, closer}
|
120 | 121 |
}
|
121 | |
return endpoints
|
|
122 |
return m
|
|
123 |
}
|
|
124 |
|
|
125 |
func migrate(prev, curr map[string]endpointCloser) map[string]endpointCloser {
|
|
126 |
for instance, ec := range prev {
|
|
127 |
if _, ok := curr[instance]; !ok {
|
|
128 |
close(ec.Closer)
|
|
129 |
}
|
|
130 |
}
|
|
131 |
return curr
|
122 | 132 |
}
|
123 | 133 |
|
124 | 134 |
func addr2instance(addr *net.SRV) string {
|
125 | 135 |
return net.JoinHostPort(addr.Target, fmt.Sprint(addr.Port))
|
126 | 136 |
}
|
|
137 |
|
|
138 |
func flatten(m map[string]endpointCloser) []endpoint.Endpoint {
|
|
139 |
a := make([]endpoint.Endpoint, 0, len(m))
|
|
140 |
for _, ec := range m {
|
|
141 |
a = append(a, ec.Endpoint)
|
|
142 |
}
|
|
143 |
return a
|
|
144 |
}
|
|
145 |
|
|
146 |
type endpointCloser struct {
|
|
147 |
endpoint.Endpoint
|
|
148 |
loadbalancer.Closer
|
|
149 |
}
|