diff --git a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java index 429e210800..f53ac28b95 100644 --- a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java @@ -101,11 +101,15 @@ final class PriorityLoadBalancer extends LoadBalancer { @Override public void handleNameResolutionError(Status error) { logger.log(XdsLogLevel.WARNING, "Received name resolution error: {0}", error); - if (children.isEmpty()) { - updateOverallState(TRANSIENT_FAILURE, new ErrorPicker(error)); - } + boolean gotoTransientFailure = true; for (ChildLbState child : children.values()) { - child.lb.handleNameResolutionError(error); + if (priorityNames.contains(child.priority)) { + child.lb.handleNameResolutionError(error); + gotoTransientFailure = false; + } + } + if (gotoTransientFailure) { + updateOverallState(TRANSIENT_FAILURE, new ErrorPicker(error)); } } diff --git a/xds/src/test/java/io/grpc/xds/PriorityLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/PriorityLoadBalancerTest.java index 1324d6f12e..95fd1e9522 100644 --- a/xds/src/test/java/io/grpc/xds/PriorityLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/PriorityLoadBalancerTest.java @@ -214,6 +214,43 @@ public class PriorityLoadBalancerTest { verify(barBalancer0, never()).shutdown(); } + @Test + public void handleNameResolutionError() { + Object fooConfig0 = new Object(); + PolicySelection fooPolicy0 = new PolicySelection(fooLbProvider, null, fooConfig0); + Object fooConfig1 = new Object(); + PolicySelection fooPolicy1 = new PolicySelection(fooLbProvider, null, fooConfig1); + + PriorityLbConfig priorityLbConfig = + new PriorityLbConfig(ImmutableMap.of("p0", fooPolicy0), ImmutableList.of("p0")); + priorityLb.handleResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()) + .setLoadBalancingPolicyConfig(priorityLbConfig) + .build()); + LoadBalancer fooLb0 = Iterables.getOnlyElement(fooBalancers); + Status status = Status.DATA_LOSS.withDescription("fake error"); + priorityLb.handleNameResolutionError(status); + verify(fooLb0).handleNameResolutionError(status); + + priorityLbConfig = + new PriorityLbConfig(ImmutableMap.of("p1", fooPolicy1), ImmutableList.of("p1")); + priorityLb.handleResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()) + .setLoadBalancingPolicyConfig(priorityLbConfig) + .build()); + assertThat(fooBalancers).hasSize(2); + LoadBalancer fooLb1 = Iterables.getLast(fooBalancers); + status = Status.UNAVAILABLE.withDescription("fake error"); + priorityLb.handleNameResolutionError(status); + // fooLb0 is deactivated but not yet deleted. However, because it is delisted by the latest + // address update, name resolution error will not be propagated to it. + verify(fooLb0, never()).shutdown(); + verify(fooLb0, never()).handleNameResolutionError(status); + verify(fooLb1).handleNameResolutionError(status); + } + @Test public void typicalPriorityFailOverFlow() { PolicySelection policy0 = new PolicySelection(fooLbProvider, null, new Object());