Skip to content
3 changes: 3 additions & 0 deletions core/src/main/java/io/grpc/util/RoundRobinLoadBalancer.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ private void updateBalancingState() {

private void updateBalancingState(ConnectivityState state, RoundRobinPicker picker) {
if (state != currentState || !picker.isEquivalentTo(currentPicker)) {
if (currentState == TRANSIENT_FAILURE && state != READY) {
return;
}
helper.updateBalancingState(state, picker);
currentState = state;
currentPicker = picker;
Expand Down
39 changes: 39 additions & 0 deletions core/src/test/java/io/grpc/util/RoundRobinLoadBalancerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,45 @@ public void pickAfterStateChange() throws Exception {
verifyNoMoreInteractions(mockHelper);
}

@Test
public void stayTransientFailureUntilReady() {
InOrder inOrder = inOrder(mockHelper);
loadBalancer.handleResolvedAddresses(
ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(Attributes.EMPTY)
.build());

inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), isA(EmptyPicker.class));

for (Subchannel sc : loadBalancer.getSubchannels()) {
deliverSubchannelState(
sc,
ConnectivityStateInfo
.forTransientFailure(Status.UNKNOWN.withDescription("connection broken")));
}
inOrder.verify(mockHelper).updateBalancingState(eq(TRANSIENT_FAILURE), isA(EmptyPicker.class));

for (Subchannel sc : loadBalancer.getSubchannels()) {
deliverSubchannelState(
sc,
ConnectivityStateInfo.forNonError(IDLE));
}
inOrder.verifyNoMoreInteractions();

for (Subchannel sc : loadBalancer.getSubchannels()) {
deliverSubchannelState(
sc,
ConnectivityStateInfo.forNonError(CONNECTING));
}
inOrder.verifyNoMoreInteractions();

Subchannel subchannel = loadBalancer.getSubchannels().iterator().next();
deliverSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(mockHelper).updateBalancingState(eq(READY), isA(ReadyPicker.class));

verify(mockHelper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
verifyNoMoreInteractions(mockHelper);
}

@Test
public void pickerRoundRobin() throws Exception {
Subchannel subchannel = mock(Subchannel.class);
Expand Down