@@ -95,7 +95,7 @@ func newCCBalancerWrapper(cc *ClientConn) *ccBalancerWrapper {
9595// it is safe to call into the balancer here.
9696func (ccb * ccBalancerWrapper ) updateClientConnState (ccs * balancer.ClientConnState ) error {
9797 errCh := make (chan error )
98- ok := ccb . serializer . Schedule ( func (ctx context.Context ) {
98+ uccs := func (ctx context.Context ) {
9999 defer close (errCh )
100100 if ctx .Err () != nil || ccb .balancer == nil {
101101 return
@@ -110,17 +110,23 @@ func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnStat
110110 logger .Infof ("error from balancer.UpdateClientConnState: %v" , err )
111111 }
112112 errCh <- err
113- })
114- if ! ok {
115- return nil
116113 }
114+ onFailure := func () { close (errCh ) }
115+
116+ // UpdateClientConnState can race with Close, and when the latter wins, the
117+ // serializer is closed, and the attempt to schedule the callback will fail.
118+ // It is acceptable to ignore this failure. But since we want to handle the
119+ // state update in a blocking fashion (when we successfully schedule the
120+ // callback), we have to use the ScheduleOr method and not the MaybeSchedule
121+ // method on the serializer.
122+ ccb .serializer .ScheduleOr (uccs , onFailure )
117123 return <- errCh
118124}
119125
120126// resolverError is invoked by grpc to push a resolver error to the underlying
121127// balancer. The call to the balancer is executed from the serializer.
122128func (ccb * ccBalancerWrapper ) resolverError (err error ) {
123- ccb .serializer .Schedule (func (ctx context.Context ) {
129+ ccb .serializer .TrySchedule (func (ctx context.Context ) {
124130 if ctx .Err () != nil || ccb .balancer == nil {
125131 return
126132 }
@@ -136,7 +142,7 @@ func (ccb *ccBalancerWrapper) close() {
136142 ccb .closed = true
137143 ccb .mu .Unlock ()
138144 channelz .Info (logger , ccb .cc .channelz , "ccBalancerWrapper: closing" )
139- ccb .serializer .Schedule (func (context.Context ) {
145+ ccb .serializer .TrySchedule (func (context.Context ) {
140146 if ccb .balancer == nil {
141147 return
142148 }
@@ -148,7 +154,7 @@ func (ccb *ccBalancerWrapper) close() {
148154
149155// exitIdle invokes the balancer's exitIdle method in the serializer.
150156func (ccb * ccBalancerWrapper ) exitIdle () {
151- ccb .serializer .Schedule (func (ctx context.Context ) {
157+ ccb .serializer .TrySchedule (func (ctx context.Context ) {
152158 if ctx .Err () != nil || ccb .balancer == nil {
153159 return
154160 }
@@ -256,7 +262,7 @@ type acBalancerWrapper struct {
256262// updateState is invoked by grpc to push a subConn state update to the
257263// underlying balancer.
258264func (acbw * acBalancerWrapper ) updateState (s connectivity.State , curAddr resolver.Address , err error ) {
259- acbw .ccb .serializer .Schedule (func (ctx context.Context ) {
265+ acbw .ccb .serializer .TrySchedule (func (ctx context.Context ) {
260266 if ctx .Err () != nil || acbw .ccb .balancer == nil {
261267 return
262268 }
0 commit comments