use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class GrpclbLoadBalancerTest method subtestGrpclbFallbackInitialTimeout.
// Fallback or not within the period of the initial timeout.
private void subtestGrpclbFallbackInitialTimeout(boolean timerExpires) {
long loadReportIntervalMillis = 1983;
InOrder inOrder = inOrder(helper, subchannelPool);
// Create balancer and backend addresses
List<EquivalentAddressGroup> backendList = createResolvedBackendAddresses(2);
List<EquivalentAddressGroup> grpclbBalancerList = createResolvedBalancerAddresses(1);
deliverResolvedAddresses(backendList, grpclbBalancerList);
inOrder.verify(helper).createOobChannel(eq(xattr(grpclbBalancerList)), eq(lbAuthority(0) + NO_USE_AUTHORITY_SUFFIX));
// Attempted to connect to balancer
assertEquals(1, fakeOobChannels.size());
ManagedChannel oobChannel = fakeOobChannels.poll();
verify(mockLbService).balanceLoad(lbResponseObserverCaptor.capture());
StreamObserver<LoadBalanceResponse> lbResponseObserver = lbResponseObserverCaptor.getValue();
assertEquals(1, lbRequestObservers.size());
StreamObserver<LoadBalanceRequest> lbRequestObserver = lbRequestObservers.poll();
verify(lbRequestObserver).onNext(eq(LoadBalanceRequest.newBuilder().setInitialRequest(InitialLoadBalanceRequest.newBuilder().setName(SERVICE_AUTHORITY).build()).build()));
lbResponseObserver.onNext(buildInitialResponse(loadReportIntervalMillis));
// We don't care if these methods have been run.
inOrder.verify(helper, atLeast(0)).getSynchronizationContext();
inOrder.verify(helper, atLeast(0)).getScheduledExecutorService();
inOrder.verifyNoMoreInteractions();
assertEquals(1, fakeClock.numPendingTasks(FALLBACK_MODE_TASK_FILTER));
fakeClock.forwardTime(GrpclbState.FALLBACK_TIMEOUT_MS - 1, TimeUnit.MILLISECONDS);
assertEquals(1, fakeClock.numPendingTasks(FALLBACK_MODE_TASK_FILTER));
// ////////////////////////////////
if (timerExpires) {
logs.clear();
fakeClock.forwardTime(1, TimeUnit.MILLISECONDS);
assertEquals(0, fakeClock.numPendingTasks(FALLBACK_MODE_TASK_FILTER));
assertThat(logs).containsExactly("INFO: [grpclb-<api.google.com>] Using fallback backends").inOrder();
// Fall back to the backends from resolver
fallbackTestVerifyUseOfFallbackBackendLists(inOrder, backendList);
assertFalse(oobChannel.isShutdown());
verify(lbRequestObserver, never()).onCompleted();
}
// ////////////////////////////////////////////////////////////////////
// Name resolver sends new resolution results without any backend addr
// ////////////////////////////////////////////////////////////////////
grpclbBalancerList = createResolvedBalancerAddresses(2);
deliverResolvedAddresses(Collections.<EquivalentAddressGroup>emptyList(), grpclbBalancerList);
// New addresses are updated to the OobChannel
inOrder.verify(helper).updateOobChannelAddresses(same(oobChannel), eq(xattr(grpclbBalancerList)));
if (timerExpires) {
// Still in fallback logic, except that the backend list is empty
for (Subchannel subchannel : mockSubchannels) {
verify(subchannelPool).returnSubchannel(eq(subchannel), any(ConnectivityStateInfo.class));
}
// RPC error status includes message of balancer RPC timeout
inOrder.verify(helper).updateBalancingState(eq(TRANSIENT_FAILURE), pickerCaptor.capture());
PickResult result = pickerCaptor.getValue().pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(result.getStatus().getDescription()).startsWith(GrpclbState.NO_FALLBACK_BACKENDS_STATUS.getDescription());
assertThat(result.getStatus().getDescription()).contains(GrpclbState.BALANCER_TIMEOUT_STATUS.getDescription());
}
// //////////////////////////////////////////////////////////////
// Name resolver sends new resolution results with backend addrs
// //////////////////////////////////////////////////////////////
// prevents the cached subchannel to be used
subchannelPool.clear();
backendList = createResolvedBackendAddresses(2);
grpclbBalancerList = createResolvedBalancerAddresses(1);
deliverResolvedAddresses(backendList, grpclbBalancerList);
// New LB address is updated to the OobChannel
inOrder.verify(helper).updateOobChannelAddresses(same(oobChannel), eq(xattr(grpclbBalancerList)));
if (timerExpires) {
// New backend addresses are used for fallback
fallbackTestVerifyUseOfFallbackBackendLists(inOrder, Arrays.asList(backendList.get(0), backendList.get(1)));
}
// //////////////////////////////////////////////
if (timerExpires) {
Status streamError = Status.UNAVAILABLE.withDescription("OOB stream broken");
lbResponseObserver.onError(streamError.asException());
// The error will NOT propagate to picker because fallback list is in use.
inOrder.verify(helper, never()).updateBalancingState(any(ConnectivityState.class), any(SubchannelPicker.class));
// A new stream is created
verify(mockLbService, times(2)).balanceLoad(lbResponseObserverCaptor.capture());
lbResponseObserver = lbResponseObserverCaptor.getValue();
assertEquals(1, lbRequestObservers.size());
lbRequestObserver = lbRequestObservers.poll();
verify(lbRequestObserver).onNext(eq(LoadBalanceRequest.newBuilder().setInitialRequest(InitialLoadBalanceRequest.newBuilder().setName(SERVICE_AUTHORITY).build()).build()));
}
// ///////////////////////////////
// Balancer returns a server list
// ///////////////////////////////
List<ServerEntry> serverList = Arrays.asList(new ServerEntry("127.0.0.1", 2000, "token0001"), new ServerEntry("127.0.0.1", 2010, "token0002"));
lbResponseObserver.onNext(buildInitialResponse());
lbResponseObserver.onNext(buildLbResponse(serverList));
// Balancer-provided server list now in effect
fallbackTestVerifyUseOfBalancerBackendLists(inOrder, serverList);
// /////////////////////////////////////////////////////////////
// New backend addresses from resolver outside of fallback mode
// /////////////////////////////////////////////////////////////
backendList = createResolvedBackendAddresses(1);
grpclbBalancerList = createResolvedBalancerAddresses(1);
deliverResolvedAddresses(backendList, grpclbBalancerList);
// Will not affect the round robin list at all
inOrder.verify(helper, never()).updateBalancingState(any(ConnectivityState.class), any(SubchannelPicker.class));
// No fallback timeout timer scheduled.
assertEquals(0, fakeClock.numPendingTasks(FALLBACK_MODE_TASK_FILTER));
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class GrpclbLoadBalancerTest method fallbackTestVerifyUseOfBackendLists.
private List<Subchannel> fallbackTestVerifyUseOfBackendLists(InOrder inOrder, List<EquivalentAddressGroup> addrs, @Nullable List<String> tokens) {
if (tokens != null) {
assertEquals(addrs.size(), tokens.size());
}
for (EquivalentAddressGroup addr : addrs) {
inOrder.verify(subchannelPool).takeOrCreateSubchannel(eq(addr), any(Attributes.class));
}
RoundRobinPicker picker = (RoundRobinPicker) currentPicker;
assertThat(picker.dropList).containsExactlyElementsIn(Collections.nCopies(addrs.size(), null));
assertThat(picker.pickList).containsExactly(GrpclbState.BUFFER_ENTRY);
assertEquals(addrs.size(), mockSubchannels.size());
ArrayList<Subchannel> subchannels = new ArrayList<>(mockSubchannels);
mockSubchannels.clear();
for (Subchannel subchannel : subchannels) {
deliverSubchannelState(subchannel, ConnectivityStateInfo.forNonError(CONNECTING));
}
inOrder.verify(helper, atLeast(0)).updateBalancingState(eq(CONNECTING), any(SubchannelPicker.class));
inOrder.verify(helper, never()).updateBalancingState(any(ConnectivityState.class), any(SubchannelPicker.class));
ArrayList<BackendEntry> pickList = new ArrayList<>();
for (int i = 0; i < addrs.size(); i++) {
Subchannel subchannel = subchannels.get(i);
BackendEntry backend;
if (tokens == null) {
backend = new BackendEntry(subchannel);
} else {
backend = new BackendEntry(subchannel, getLoadRecorder(), tokens.get(i));
}
pickList.add(backend);
deliverSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(helper).updateBalancingState(eq(READY), pickerCaptor.capture());
picker = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker.dropList).containsExactlyElementsIn(Collections.nCopies(addrs.size(), null));
assertThat(picker.pickList).containsExactlyElementsIn(pickList);
inOrder.verify(helper, never()).updateBalancingState(any(ConnectivityState.class), any(SubchannelPicker.class));
}
return subchannels;
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class GrpclbLoadBalancerTest method roundRobinPickerWithDrop.
@Test
public void roundRobinPickerWithDrop() {
assertTrue(DROP_PICK_RESULT.isDrop());
GrpclbClientLoadRecorder loadRecorder = new GrpclbClientLoadRecorder(fakeClock.getTimeProvider());
Subchannel subchannel = mock(Subchannel.class);
// 1 out of 2 requests are to be dropped
DropEntry d = new DropEntry(loadRecorder, "LBTOKEN0003");
List<DropEntry> dropList = Arrays.asList(null, d);
BackendEntry b1 = new BackendEntry(subchannel, loadRecorder, "LBTOKEN0001");
BackendEntry b2 = new BackendEntry(subchannel, loadRecorder, "LBTOKEN0002");
List<BackendEntry> pickList = Arrays.asList(b1, b2);
RoundRobinPicker picker = new RoundRobinPicker(dropList, pickList);
// dropList[0], pickList[0]
PickSubchannelArgs args1 = mock(PickSubchannelArgs.class);
Metadata headers1 = new Metadata();
headers1.put(GrpclbConstants.TOKEN_METADATA_KEY, "LBTOKEN__OLD");
when(args1.getHeaders()).thenReturn(headers1);
assertSame(b1.result, picker.pickSubchannel(args1));
verify(args1).getHeaders();
assertThat(headers1.getAll(GrpclbConstants.TOKEN_METADATA_KEY)).containsExactly("LBTOKEN0001");
// dropList[1]: drop
PickSubchannelArgs args2 = mock(PickSubchannelArgs.class);
Metadata headers2 = new Metadata();
when(args2.getHeaders()).thenReturn(headers2);
assertSame(DROP_PICK_RESULT, picker.pickSubchannel(args2));
verify(args2, never()).getHeaders();
// dropList[0], pickList[1]
PickSubchannelArgs args3 = mock(PickSubchannelArgs.class);
Metadata headers3 = new Metadata();
when(args3.getHeaders()).thenReturn(headers3);
assertSame(b2.result, picker.pickSubchannel(args3));
verify(args3).getHeaders();
assertThat(headers3.getAll(GrpclbConstants.TOKEN_METADATA_KEY)).containsExactly("LBTOKEN0002");
// dropList[1]: drop
PickSubchannelArgs args4 = mock(PickSubchannelArgs.class);
Metadata headers4 = new Metadata();
when(args4.getHeaders()).thenReturn(headers4);
assertSame(DROP_PICK_RESULT, picker.pickSubchannel(args4));
verify(args4, never()).getHeaders();
// dropList[0], pickList[0]
PickSubchannelArgs args5 = mock(PickSubchannelArgs.class);
Metadata headers5 = new Metadata();
when(args5.getHeaders()).thenReturn(headers5);
assertSame(b1.result, picker.pickSubchannel(args5));
verify(args5).getHeaders();
assertThat(headers5.getAll(GrpclbConstants.TOKEN_METADATA_KEY)).containsExactly("LBTOKEN0001");
verify(subchannel, never()).getAttributes();
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class GrpclbLoadBalancerTest method tearDown.
@After
public void tearDown() {
try {
if (balancer != null) {
syncContext.execute(new Runnable() {
@Override
public void run() {
balancer.shutdown();
}
});
}
for (ManagedChannel channel : oobChannelTracker) {
assertTrue(channel + " is shutdown", channel.isShutdown());
// balancer should have closed the LB stream, terminating the OOB channel.
assertTrue(channel + " is terminated", channel.isTerminated());
}
for (Subchannel subchannel : unpooledSubchannelTracker) {
verify(subchannel).shutdown();
}
// No timer should linger after shutdown
assertThat(fakeClock.getPendingTasks()).isEmpty();
} finally {
if (fakeLbServer != null) {
fakeLbServer.shutdownNow();
}
}
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class GrpclbState method shutdown.
void shutdown() {
logger.log(ChannelLogLevel.INFO, "[grpclb-<{0}>] Shutdown", serviceName);
shutdownLbComm();
switch(config.getMode()) {
case ROUND_ROBIN:
// testing.
for (Subchannel subchannel : subchannels.values()) {
returnSubchannelToPool(subchannel);
}
subchannelPool.clear();
break;
case PICK_FIRST:
if (!subchannels.isEmpty()) {
checkState(subchannels.size() == 1, "Excessive Subchannels: %s", subchannels);
subchannels.values().iterator().next().shutdown();
}
break;
default:
throw new AssertionError("Missing case for " + config.getMode());
}
subchannels = Collections.emptyMap();
cancelFallbackTimer();
cancelLbRpcRetryTimer();
}
Aggregations