@@ -333,7 +333,9 @@ func (a *authority) adsResourceUpdate(serverConfig *ServerConfig, rType Resource
333
333
//
334
334
// Only executed in the context of a serializer callback.
335
335
func (a * authority ) handleADSResourceUpdate (serverConfig * ServerConfig , rType ResourceType , updates map [string ]dataAndErrTuple , md xdsresource.UpdateMetadata , onDone func ()) {
336
- a .handleRevertingToPrimaryOnUpdate (serverConfig )
336
+ if ! a .handleRevertingToPrimaryOnUpdate (serverConfig ) {
337
+ return
338
+ }
337
339
338
340
// We build a list of callback funcs to invoke, and invoke them at the end
339
341
// of this method instead of inline (when handling the update for a
@@ -551,23 +553,47 @@ func (a *authority) handleADSResourceDoesNotExist(rType ResourceType, resourceNa
551
553
// lower priority servers are closed and the active server is reverted to the
552
554
// highest priority server that sent the update.
553
555
//
556
+ // The return value indicates whether subsequent processing of the resource
557
+ // update should continue or not.
558
+ //
554
559
// This method is only executed in the context of a serializer callback.
555
- func (a * authority ) handleRevertingToPrimaryOnUpdate (serverConfig * ServerConfig ) {
556
- if a .activeXDSChannel != nil && isServerConfigEqual (serverConfig , a .activeXDSChannel .serverConfig ) {
560
+ func (a * authority ) handleRevertingToPrimaryOnUpdate (serverConfig * ServerConfig ) bool {
561
+ if a .activeXDSChannel == nil {
562
+ // This can happen only when all watches on this authority have been
563
+ // removed, and the xdsChannels have been closed. This update should
564
+ // have been received prior to closing of the channel, and therefore
565
+ // must be ignored.
566
+ return false
567
+ }
568
+
569
+ if isServerConfigEqual (serverConfig , a .activeXDSChannel .serverConfig ) {
557
570
// If the resource update is from the current active server, nothing
558
571
// needs to be done from fallback point of view.
559
- return
572
+ return true
560
573
}
561
574
562
575
if a .logger .V (2 ) {
563
576
a .logger .Infof ("Received update from non-active server %q" , serverConfig )
564
577
}
565
578
566
579
// If the resource update is not from the current active server, it means
567
- // that we have received an update from a higher priority server and we need
568
- // to revert back to it. This method guarantees that when an update is
569
- // received from a server, all lower priority servers are closed.
580
+ // that we have received an update either from:
581
+ // - a server that has a higher priority than the current active server and
582
+ // therefore we need to revert back to it and close all lower priority
583
+ // servers, or,
584
+ // - a server that has a lower priority than the current active server. This
585
+ // can happen when the server close and the response race against each
586
+ // other. We can safely ignore this update, since we have already reverted
587
+ // to the higher priority server, and closed all lower priority servers.
570
588
serverIdx := a .serverIndexForConfig (serverConfig )
589
+ activeServerIdx := a .serverIndexForConfig (a .activeXDSChannel .serverConfig )
590
+ if activeServerIdx < serverIdx {
591
+ return false
592
+ }
593
+
594
+ // At this point, we are guaranteed that we have received a response from a
595
+ // higher priority server compared to the current active server. So, we
596
+ // revert to the higher priorty server and close all lower priority ones.
571
597
a .activeXDSChannel = a .xdsChannelConfigs [serverIdx ]
572
598
573
599
// Close all lower priority channels.
@@ -605,6 +631,7 @@ func (a *authority) handleRevertingToPrimaryOnUpdate(serverConfig *ServerConfig)
605
631
}
606
632
cfg .channel = nil
607
633
}
634
+ return true
608
635
}
609
636
610
637
// watchResource registers a new watcher for the specified resource type and
0 commit comments