@@ -66,7 +66,9 @@ type endpointSharding struct {
66
66
cc balancer.ClientConn
67
67
bOpts balancer.BuildOptions
68
68
69
+ childMu sync.Mutex // syncs balancer.Balancer calls into children
69
70
children atomic.Pointer [resolver.EndpointMap ]
71
+ closed bool
70
72
71
73
// inhibitChildUpdates is set during UpdateClientConnState/ResolverError
72
74
// calls (calls to children will each produce an update, only want one
@@ -83,6 +85,9 @@ type endpointSharding struct {
83
85
// addresses it will ignore that endpoint. Otherwise, returns first error found
84
86
// from a child, but fully processes the new update.
85
87
func (es * endpointSharding ) UpdateClientConnState (state balancer.ClientConnState ) error {
88
+ es .childMu .Lock ()
89
+ defer es .childMu .Unlock ()
90
+
86
91
es .inhibitChildUpdates .Store (true )
87
92
defer func () {
88
93
es .inhibitChildUpdates .Store (false )
@@ -145,6 +150,8 @@ func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState
145
150
// children and sends a single synchronous update of the childStates at the end
146
151
// of the ResolverError operation.
147
152
func (es * endpointSharding ) ResolverError (err error ) {
153
+ es .childMu .Lock ()
154
+ defer es .childMu .Unlock ()
148
155
es .inhibitChildUpdates .Store (true )
149
156
defer func () {
150
157
es .inhibitChildUpdates .Store (false )
@@ -162,11 +169,14 @@ func (es *endpointSharding) UpdateSubConnState(balancer.SubConn, balancer.SubCon
162
169
}
163
170
164
171
func (es * endpointSharding ) Close () {
172
+ es .childMu .Lock ()
173
+ defer es .childMu .Unlock ()
165
174
children := es .children .Load ()
166
175
for _ , child := range children .Values () {
167
176
bal := child .(balancer.Balancer )
168
177
bal .Close ()
169
178
}
179
+ es .closed = true
170
180
}
171
181
172
182
// updateState updates this component's state. It sends the aggregated state,
@@ -274,6 +284,17 @@ func (bw *balancerWrapper) UpdateState(state balancer.State) {
274
284
bw .es .mu .Lock ()
275
285
bw .childState .State = state
276
286
bw .es .mu .Unlock ()
287
+ // When a child balancer says it's IDLE, ping it to exit idle and reconnect.
288
+ // TODO: In the future, perhaps make this a knob in configuration.
289
+ if ei , ok := bw .Balancer .(balancer.ExitIdler ); state .ConnectivityState == connectivity .Idle && ok {
290
+ go func () {
291
+ bw .es .childMu .Lock ()
292
+ if ! bw .es .closed {
293
+ ei .ExitIdle ()
294
+ }
295
+ bw .es .childMu .Unlock ()
296
+ }()
297
+ }
277
298
bw .es .updateState ()
278
299
}
279
300
0 commit comments