use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class LeastRequestLoadBalancerTest method pickAfterStateChange.
@Test
public void pickAfterStateChange() throws Exception {
InOrder inOrder = inOrder(mockHelper);
loadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(Attributes.EMPTY).build());
Subchannel subchannel = loadBalancer.getSubchannels().iterator().next();
Ref<ConnectivityStateInfo> subchannelStateInfo = subchannel.getAttributes().get(STATE_INFO);
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), isA(EmptyPicker.class));
assertThat(subchannelStateInfo.value).isEqualTo(ConnectivityStateInfo.forNonError(IDLE));
deliverSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(mockHelper).updateBalancingState(eq(READY), pickerCaptor.capture());
assertThat(pickerCaptor.getValue()).isInstanceOf(ReadyPicker.class);
assertThat(subchannelStateInfo.value).isEqualTo(ConnectivityStateInfo.forNonError(READY));
Status error = Status.UNKNOWN.withDescription("¯\\_(ツ)_//¯");
deliverSubchannelState(subchannel, ConnectivityStateInfo.forTransientFailure(error));
assertThat(subchannelStateInfo.value.getState()).isEqualTo(TRANSIENT_FAILURE);
assertThat(subchannelStateInfo.value.getStatus()).isEqualTo(error);
inOrder.verify(mockHelper).refreshNameResolution();
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
assertThat(pickerCaptor.getValue()).isInstanceOf(EmptyPicker.class);
deliverSubchannelState(subchannel, ConnectivityStateInfo.forNonError(IDLE));
inOrder.verify(mockHelper).refreshNameResolution();
assertThat(subchannelStateInfo.value.getState()).isEqualTo(TRANSIENT_FAILURE);
assertThat(subchannelStateInfo.value.getStatus()).isEqualTo(error);
verify(subchannel, times(2)).requestConnection();
verify(mockHelper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
verifyNoMoreInteractions(mockHelper);
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class CachedSubchannelPool method takeOrCreateSubchannel.
@Override
public Subchannel takeOrCreateSubchannel(EquivalentAddressGroup eag, Attributes defaultAttributes) {
final CacheEntry entry = cache.remove(eag);
final Subchannel subchannel;
if (entry == null) {
subchannel = helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(eag).setAttributes(defaultAttributes).build());
subchannel.start(new SubchannelStateListener() {
@Override
public void onSubchannelState(ConnectivityStateInfo newState) {
updateCachedSubchannelState(subchannel, newState);
listener.onSubchannelState(subchannel, newState);
}
});
} else {
subchannel = entry.subchannel;
entry.shutdownTimer.cancel();
// Make the balancer up-to-date with the latest state in case it has changed while it's
// in the cache.
helper.getSynchronizationContext().execute(new Runnable() {
@Override
public void run() {
listener.onSubchannelState(subchannel, entry.state);
}
});
}
return subchannel;
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class GrpclbState method updateServerList.
/**
* Populate backend servers to be used based on the given list of addresses.
*/
private void updateServerList(List<DropEntry> newDropList, List<BackendAddressGroup> newBackendAddrList, @Nullable GrpclbClientLoadRecorder loadRecorder) {
HashMap<List<EquivalentAddressGroup>, Subchannel> newSubchannelMap = new HashMap<>();
List<BackendEntry> newBackendList = new ArrayList<>();
switch(config.getMode()) {
case ROUND_ROBIN:
for (BackendAddressGroup backendAddr : newBackendAddrList) {
EquivalentAddressGroup eag = backendAddr.getAddresses();
List<EquivalentAddressGroup> eagAsList = Collections.singletonList(eag);
Subchannel subchannel = newSubchannelMap.get(eagAsList);
if (subchannel == null) {
subchannel = subchannels.get(eagAsList);
if (subchannel == null) {
subchannel = subchannelPool.takeOrCreateSubchannel(eag, createSubchannelAttrs());
subchannel.requestConnection();
}
newSubchannelMap.put(eagAsList, subchannel);
}
BackendEntry entry;
// Only picks with tokens are reported to LoadRecorder
if (backendAddr.getToken() == null) {
entry = new BackendEntry(subchannel);
} else {
entry = new BackendEntry(subchannel, loadRecorder, backendAddr.getToken());
}
newBackendList.add(entry);
}
// Close Subchannels whose addresses have been delisted
for (Map.Entry<List<EquivalentAddressGroup>, Subchannel> entry : subchannels.entrySet()) {
List<EquivalentAddressGroup> eagList = entry.getKey();
if (!newSubchannelMap.containsKey(eagList)) {
returnSubchannelToPool(entry.getValue());
}
}
subchannels = Collections.unmodifiableMap(newSubchannelMap);
break;
case PICK_FIRST:
checkState(subchannels.size() <= 1, "Unexpected Subchannel count: %s", subchannels);
final Subchannel subchannel;
if (newBackendAddrList.isEmpty()) {
if (subchannels.size() == 1) {
subchannel = subchannels.values().iterator().next();
subchannel.shutdown();
subchannels = Collections.emptyMap();
}
break;
}
List<EquivalentAddressGroup> eagList = new ArrayList<>();
// The PICK_FIRST code path doesn't cache Subchannels.
for (BackendAddressGroup bag : newBackendAddrList) {
EquivalentAddressGroup origEag = bag.getAddresses();
Attributes eagAttrs = origEag.getAttributes();
if (bag.getToken() != null) {
eagAttrs = eagAttrs.toBuilder().set(GrpclbConstants.TOKEN_ATTRIBUTE_KEY, bag.getToken()).build();
}
eagList.add(new EquivalentAddressGroup(origEag.getAddresses(), eagAttrs));
}
if (subchannels.isEmpty()) {
subchannel = helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(eagList).setAttributes(createSubchannelAttrs()).build());
subchannel.start(new SubchannelStateListener() {
@Override
public void onSubchannelState(ConnectivityStateInfo newState) {
handleSubchannelState(subchannel, newState);
}
});
if (requestConnectionPending) {
subchannel.requestConnection();
requestConnectionPending = false;
}
} else {
subchannel = subchannels.values().iterator().next();
subchannel.updateAddresses(eagList);
}
subchannels = Collections.singletonMap(eagList, subchannel);
newBackendList.add(new BackendEntry(subchannel, new TokenAttachingTracerFactory(loadRecorder)));
break;
default:
throw new AssertionError("Missing case for " + config.getMode());
}
dropList = Collections.unmodifiableList(newDropList);
backendList = Collections.unmodifiableList(newBackendList);
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class HealthCheckingLoadBalancerFactoryTest method serviceConfigChangesServiceNameWhenRpcInactive.
@Test
public void serviceConfigChangesServiceNameWhenRpcInactive() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
ResolvedAddresses result1 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result1);
verify(origLb).handleResolvedAddresses(result1);
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
SubchannelStateListener mockListener = mockStateListeners[0];
assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[0]);
InOrder inOrder = inOrder(origLb, mockListener);
HealthImpl healthImpl = healthImpls[0];
// Underlying subchannel is not READY initially
ConnectivityStateInfo underlyingErrorState = ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE.withDescription("connection refused"));
deliverSubchannelState(0, underlyingErrorState);
inOrder.verify(mockListener).onSubchannelState(same(underlyingErrorState));
inOrder.verifyNoMoreInteractions();
// Service config returns with the same health check name.
hcLbEventDelivery.handleResolvedAddresses(result1);
// It's delivered to origLb, but nothing else happens
inOrder.verify(origLb).handleResolvedAddresses(result1);
assertThat(healthImpl.calls).isEmpty();
verifyNoMoreInteractions(origLb);
// Service config returns a different health check name.
resolutionAttrs = attrsWithHealthCheckService("FooService");
ResolvedAddresses result2 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result2);
inOrder.verify(origLb).handleResolvedAddresses(result2);
// Underlying subchannel is now ready
deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
// Concluded CONNECTING state
inOrder.verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
// Health check RPC is started
assertThat(healthImpl.calls).hasSize(1);
// with the new service name
assertThat(healthImpl.calls.poll().request).isEqualTo(makeRequest("FooService"));
verifyNoMoreInteractions(origLb, mockListener);
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class HealthCheckingLoadBalancerFactoryTest method serviceConfigDisablesHealthCheckWhenRpcInactive.
@Test
public void serviceConfigDisablesHealthCheckWhenRpcInactive() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
ResolvedAddresses result1 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result1);
verify(origLb).handleResolvedAddresses(result1);
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[0]);
InOrder inOrder = inOrder(origLb, mockStateListeners[0]);
// Underlying subchannel is not READY initially
ConnectivityStateInfo underlyingErrorState = ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE.withDescription("connection refused"));
deliverSubchannelState(0, underlyingErrorState);
inOrder.verify(mockStateListeners[0]).onSubchannelState(same(underlyingErrorState));
inOrder.verifyNoMoreInteractions();
// NameResolver gives an update without service config, thus health check will be disabled
ResolvedAddresses result2 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(Attributes.EMPTY).build();
hcLbEventDelivery.handleResolvedAddresses(result2);
inOrder.verify(origLb).handleResolvedAddresses(result2);
// Underlying subchannel is now ready
deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
// Since health check is disabled, READY state is propagated directly.
inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
// and there is no health check activity.
assertThat(healthImpls[0].calls).isEmpty();
verifyNoMoreInteractions(origLb, mockStateListeners[0]);
}
Aggregations