diff --git a/xds/src/main/java/io/grpc/xds/EdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/EdsLoadBalancer2.java index ece7baf742..4ba768030a 100644 --- a/xds/src/main/java/io/grpc/xds/EdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/EdsLoadBalancer2.java @@ -275,10 +275,8 @@ final class EdsLoadBalancer2 extends LoadBalancer { locality, localityLbInfo.getLocalityWeight()); } if (prioritizedLocalityWeights.isEmpty()) { - lbHelper.helper.updateBalancingState( - TRANSIENT_FAILURE, - new ErrorPicker( - Status.UNAVAILABLE.withDescription("No usable priority/locality/endpoint"))); + propagateResourceError( + Status.UNAVAILABLE.withDescription("No usable priority/locality/endpoint")); return; } if (lb == null) { @@ -310,15 +308,8 @@ final class EdsLoadBalancer2 extends LoadBalancer { @Override public void onResourceDoesNotExist(String resourceName) { logger.log(XdsLogLevel.INFO, "Resource {0} is unavailable", resourceName); - if (lb != null) { - lb.shutdown(); - lb = null; - } - lbHelper.helper.updateBalancingState( - TRANSIENT_FAILURE, - new ErrorPicker( - Status.UNAVAILABLE.withDescription( - "Resource " + resourceName + " is unavailable"))); + propagateResourceError( + Status.UNAVAILABLE.withDescription("Resource " + resourceName + " is unavailable")); } @Override @@ -330,6 +321,14 @@ final class EdsLoadBalancer2 extends LoadBalancer { } } + private void propagateResourceError(Status error) { + if (lb != null) { + lb.shutdown(); + lb = null; + } + lbHelper.helper.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(error)); + } + private final class DropHandlingLbHelper extends ForwardingLoadBalancerHelper { private final Helper helper; private List dropPolicies = Collections.emptyList(); diff --git a/xds/src/test/java/io/grpc/xds/EdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/EdsLoadBalancer2Test.java index ecb83c9460..8ceb5f7ded 100644 --- a/xds/src/test/java/io/grpc/xds/EdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/EdsLoadBalancer2Test.java @@ -406,6 +406,27 @@ public class EdsLoadBalancer2Test { .isEqualTo("No usable priority/locality/endpoint"); } + @Test + public void handleEndpointResource_shutDownExistingChildLbPoliciesIfNoUsableEndpoints() { + deliverSimpleClusterLoadAssignment(EDS_SERVICE_NAME); + FakeLoadBalancer childBalancer = Iterables.getOnlyElement(downstreamBalancers); + assertThat(childBalancer.shutdown).isFalse(); + + EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); + LocalityLbEndpoints localityLbEndpoints1 = + buildLocalityLbEndpoints(1, 10, Collections.singletonMap(endpoint1, false)); + xdsClient.deliverClusterLoadAssignment( + EDS_SERVICE_NAME, Collections.singletonMap(locality1, localityLbEndpoints1)); + + assertThat(childBalancer.shutdown).isTrue(); + assertThat(currentState).isEqualTo(ConnectivityState.TRANSIENT_FAILURE); + PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class)); + assertThat(result.getStatus().isOk()).isFalse(); + assertThat(result.getStatus().getCode()).isEqualTo(Code.UNAVAILABLE); + assertThat(result.getStatus().getDescription()) + .isEqualTo("No usable priority/locality/endpoint"); + } + @Test public void handleDrops() { FakeLoadBalancerProvider fakeRoundRobinProvider = new FakeLoadBalancerProvider("round_robin");