Search in sources :

Example 6 with SubchannelStateListener

use of io.grpc.LoadBalancer.SubchannelStateListener 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);
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) InOrder(org.mockito.InOrder) ConnectivityStateInfo(io.grpc.ConnectivityStateInfo) Subchannel(io.grpc.LoadBalancer.Subchannel) Attributes(io.grpc.Attributes) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 7 with SubchannelStateListener

use of io.grpc.LoadBalancer.SubchannelStateListener in project grpc-java by grpc.

the class HealthCheckingLoadBalancerFactoryTest method backoffRetriesWhenServerErroneouslyClosesRpcBeforeAnyResponse.

@Test
public void backoffRetriesWhenServerErroneouslyClosesRpcBeforeAnyResponse() {
    Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
    ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result);
    verify(origLb).handleResolvedAddresses(result);
    verifyNoMoreInteractions(origLb);
    FakeSubchannel subchannel = unwrap(createSubchannel(0, Attributes.EMPTY));
    assertThat(subchannel).isSameInstanceAs(subchannels[0]);
    SubchannelStateListener mockListener = mockStateListeners[0];
    InOrder inOrder = inOrder(mockListener, backoffPolicyProvider, backoffPolicy1, backoffPolicy2);
    deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
    inOrder.verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    HealthImpl healthImpl = healthImpls[0];
    assertThat(healthImpl.calls).hasSize(1);
    assertThat(clock.getPendingTasks()).isEmpty();
    subchannel.logs.clear();
    // Server closes the health checking RPC without any response
    healthImpl.calls.poll().responseObserver.onCompleted();
    // which results in TRANSIENT_FAILURE
    inOrder.verify(mockListener).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.OK + " for 'TeeService'"));
    assertThat(subchannel.logs).containsExactly("INFO: TRANSIENT_FAILURE: health-check stream closed with " + Status.OK, "DEBUG: Will retry health-check after 11 ns").inOrder();
    // Retry with backoff is scheduled
    inOrder.verify(backoffPolicyProvider).get();
    inOrder.verify(backoffPolicy1).nextBackoffNanos();
    assertThat(clock.getPendingTasks()).hasSize(1);
    verifyRetryAfterNanos(inOrder, mockListener, healthImpl, 11);
    assertThat(clock.getPendingTasks()).isEmpty();
    subchannel.logs.clear();
    // Server closes the health checking RPC without any response
    healthImpl.calls.poll().responseObserver.onError(Status.CANCELLED.asException());
    // which also results in TRANSIENT_FAILURE, with a different description
    inOrder.verify(mockListener).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.CANCELLED + " for 'TeeService'"));
    assertThat(subchannel.logs).containsExactly("INFO: TRANSIENT_FAILURE: health-check stream closed with " + Status.CANCELLED, "DEBUG: Will retry health-check after 21 ns").inOrder();
    // Retry with backoff
    inOrder.verify(backoffPolicy1).nextBackoffNanos();
    verifyRetryAfterNanos(inOrder, mockListener, healthImpl, 21);
    // Server responds this time
    healthImpl.calls.poll().responseObserver.onNext(makeResponse(ServingStatus.SERVING));
    inOrder.verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
    verifyNoMoreInteractions(origLb, mockListener, backoffPolicyProvider, backoffPolicy1);
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) InOrder(org.mockito.InOrder) Attributes(io.grpc.Attributes) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 8 with SubchannelStateListener

use of io.grpc.LoadBalancer.SubchannelStateListener in project grpc-java by grpc.

the class HealthCheckingLoadBalancerFactoryTest method balancerShutdown.

@Test
public void balancerShutdown() {
    Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
    ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result);
    verify(origLb).handleResolvedAddresses(result);
    verifyNoMoreInteractions(origLb);
    ServerSideCall[] serverCalls = new ServerSideCall[NUM_SUBCHANNELS];
    final Subchannel[] wrappedSubchannels = new Subchannel[NUM_SUBCHANNELS];
    for (int i = 0; i < NUM_SUBCHANNELS; i++) {
        Subchannel subchannel = createSubchannel(i, Attributes.EMPTY);
        wrappedSubchannels[i] = subchannel;
        SubchannelStateListener mockListener = mockStateListeners[i];
        assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[i]);
        // Trigger the health check
        deliverSubchannelState(i, ConnectivityStateInfo.forNonError(READY));
        HealthImpl healthImpl = healthImpls[i];
        assertThat(healthImpl.calls).hasSize(1);
        serverCalls[i] = healthImpl.calls.poll();
        assertThat(serverCalls[i].cancelled).isFalse();
        verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    }
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) {
            for (int i = 0; i < NUM_SUBCHANNELS; i++) {
                wrappedSubchannels[i].shutdown();
            }
            return null;
        }
    }).when(origLb).shutdown();
    // Shut down the balancer
    hcLbEventDelivery.shutdown();
    verify(origLb).shutdown();
    // Health check stream should be cancelled
    for (int i = 0; i < NUM_SUBCHANNELS; i++) {
        assertThat(serverCalls[i].cancelled).isTrue();
        verifyNoMoreInteractions(origLb);
        verify(mockStateListeners[i]).onSubchannelState(ConnectivityStateInfo.forNonError(SHUTDOWN));
        // No more health check call is made or scheduled
        assertThat(healthImpls[i].calls).isEmpty();
    }
    assertThat(clock.getPendingTasks()).isEmpty();
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) Attributes(io.grpc.Attributes) Subchannel(io.grpc.LoadBalancer.Subchannel) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 9 with SubchannelStateListener

use of io.grpc.LoadBalancer.SubchannelStateListener in project grpc-java by grpc.

the class ManagedChannelImplTest method subtestCallsAndShutdown.

private void subtestCallsAndShutdown(boolean shutdownNow, boolean shutdownNowAfterShutdown) {
    FakeNameResolverFactory nameResolverFactory = new FakeNameResolverFactory.Builder(expectedUri).build();
    channelBuilder.nameResolverFactory(nameResolverFactory);
    createChannel();
    verify(executorPool).getObject();
    ClientStream mockStream = mock(ClientStream.class);
    ClientStream mockStream2 = mock(ClientStream.class);
    Metadata headers = new Metadata();
    Metadata headers2 = new Metadata();
    // Configure the picker so that first RPC goes to delayed transport, and second RPC goes to
    // real transport.
    Subchannel subchannel = createSubchannelSafely(helper, addressGroup, Attributes.EMPTY, subchannelStateListener);
    requestConnectionSafely(helper, subchannel);
    verify(mockTransportFactory).newClientTransport(any(SocketAddress.class), any(ClientTransportOptions.class), any(ChannelLogger.class));
    MockClientTransportInfo transportInfo = transports.poll();
    ConnectionClientTransport mockTransport = transportInfo.transport;
    verify(mockTransport).start(any(ManagedClientTransport.Listener.class));
    ManagedClientTransport.Listener transportListener = transportInfo.listener;
    when(mockTransport.newStream(same(method), same(headers), same(CallOptions.DEFAULT), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockStream);
    when(mockTransport.newStream(same(method), same(headers2), same(CallOptions.DEFAULT), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockStream2);
    transportListener.transportReady();
    when(mockPicker.pickSubchannel(new PickSubchannelArgsImpl(method, headers, CallOptions.DEFAULT))).thenReturn(PickResult.withNoResult());
    when(mockPicker.pickSubchannel(new PickSubchannelArgsImpl(method, headers2, CallOptions.DEFAULT))).thenReturn(PickResult.withSubchannel(subchannel));
    updateBalancingStateSafely(helper, READY, mockPicker);
    // First RPC, will be pending
    ClientCall<String, Integer> call = channel.newCall(method, CallOptions.DEFAULT);
    verify(mockTransportFactory).newClientTransport(any(SocketAddress.class), any(ClientTransportOptions.class), any(ChannelLogger.class));
    call.start(mockCallListener, headers);
    verify(mockTransport, never()).newStream(same(method), same(headers), same(CallOptions.DEFAULT), ArgumentMatchers.<ClientStreamTracer[]>any());
    // Second RPC, will be assigned to the real transport
    ClientCall<String, Integer> call2 = channel.newCall(method, CallOptions.DEFAULT);
    call2.start(mockCallListener2, headers2);
    verify(mockTransport).newStream(same(method), same(headers2), same(CallOptions.DEFAULT), ArgumentMatchers.<ClientStreamTracer[]>any());
    verify(mockTransport).newStream(same(method), same(headers2), same(CallOptions.DEFAULT), ArgumentMatchers.<ClientStreamTracer[]>any());
    verify(mockStream2).start(any(ClientStreamListener.class));
    // Shutdown
    if (shutdownNow) {
        channel.shutdownNow();
    } else {
        channel.shutdown();
        if (shutdownNowAfterShutdown) {
            channel.shutdownNow();
            shutdownNow = true;
        }
    }
    assertTrue(channel.isShutdown());
    assertFalse(channel.isTerminated());
    assertThat(nameResolverFactory.resolvers).hasSize(1);
    verify(mockLoadBalancerProvider).newLoadBalancer(any(Helper.class));
    // Further calls should fail without going to the transport
    ClientCall<String, Integer> call3 = channel.newCall(method, CallOptions.DEFAULT);
    call3.start(mockCallListener3, headers2);
    timer.runDueTasks();
    executor.runDueTasks();
    verify(mockCallListener3).onClose(statusCaptor.capture(), any(Metadata.class));
    assertSame(Status.Code.UNAVAILABLE, statusCaptor.getValue().getCode());
    if (shutdownNow) {
        // LoadBalancer and NameResolver are shut down as soon as delayed transport is terminated.
        verify(mockLoadBalancer).shutdown();
        assertTrue(nameResolverFactory.resolvers.get(0).shutdown);
        // call should have been aborted by delayed transport
        executor.runDueTasks();
        verify(mockCallListener).onClose(same(ManagedChannelImpl.SHUTDOWN_NOW_STATUS), any(Metadata.class));
    } else {
        // LoadBalancer and NameResolver are still running.
        verify(mockLoadBalancer, never()).shutdown();
        assertFalse(nameResolverFactory.resolvers.get(0).shutdown);
        // call and call2 are still alive, and can still be assigned to a real transport
        SubchannelPicker picker2 = mock(SubchannelPicker.class);
        when(picker2.pickSubchannel(new PickSubchannelArgsImpl(method, headers, CallOptions.DEFAULT))).thenReturn(PickResult.withSubchannel(subchannel));
        updateBalancingStateSafely(helper, READY, picker2);
        executor.runDueTasks();
        verify(mockTransport).newStream(same(method), same(headers), same(CallOptions.DEFAULT), ArgumentMatchers.<ClientStreamTracer[]>any());
        verify(mockStream).start(any(ClientStreamListener.class));
    }
    // After call is moved out of delayed transport, LoadBalancer, NameResolver and the transports
    // will be shutdown.
    verify(mockLoadBalancer).shutdown();
    assertTrue(nameResolverFactory.resolvers.get(0).shutdown);
    if (shutdownNow) {
        // Channel shutdownNow() all subchannels after shutting down LoadBalancer
        verify(mockTransport).shutdownNow(ManagedChannelImpl.SHUTDOWN_NOW_STATUS);
    } else {
        verify(mockTransport, never()).shutdownNow(any(Status.class));
    }
    // LoadBalancer should shutdown the subchannel
    shutdownSafely(helper, subchannel);
    if (shutdownNow) {
        verify(mockTransport).shutdown(same(ManagedChannelImpl.SHUTDOWN_NOW_STATUS));
    } else {
        verify(mockTransport).shutdown(same(ManagedChannelImpl.SHUTDOWN_STATUS));
    }
    // Killing the remaining real transport will terminate the channel
    transportListener.transportShutdown(Status.UNAVAILABLE);
    assertFalse(channel.isTerminated());
    verify(executorPool, never()).returnObject(any());
    transportListener.transportTerminated();
    assertTrue(channel.isTerminated());
    verify(executorPool).returnObject(executor.getScheduledExecutorService());
    verifyNoMoreInteractions(balancerRpcExecutorPool);
    verify(mockTransportFactory).newClientTransport(any(SocketAddress.class), any(ClientTransportOptions.class), any(ChannelLogger.class));
    verify(mockTransportFactory).close();
    verify(mockTransport, atLeast(0)).getLogId();
    verifyNoMoreInteractions(mockTransport);
}
Also used : Status(io.grpc.Status) ClientStreamTracer(io.grpc.ClientStreamTracer) SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) ClientTransportOptions(io.grpc.internal.ClientTransportFactory.ClientTransportOptions) Metadata(io.grpc.Metadata) MockClientTransportInfo(io.grpc.internal.TestUtils.MockClientTransportInfo) Helper(io.grpc.LoadBalancer.Helper) SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) ForwardingSubchannel(io.grpc.util.ForwardingSubchannel) Subchannel(io.grpc.LoadBalancer.Subchannel) ChannelLogger(io.grpc.ChannelLogger) ProxiedSocketAddress(io.grpc.ProxiedSocketAddress) SocketAddress(java.net.SocketAddress)

Example 10 with SubchannelStateListener

use of io.grpc.LoadBalancer.SubchannelStateListener in project grpc-java by grpc.

the class ManagedChannelImplTest method subchannelConnectionBroken_ResolverRefreshedByLb.

@Test
public void subchannelConnectionBroken_ResolverRefreshedByLb() {
    FakeNameResolverFactory nameResolverFactory = new FakeNameResolverFactory.Builder(expectedUri).setServers(Collections.singletonList(new EquivalentAddressGroup(socketAddress))).build();
    channelBuilder.nameResolverFactory(nameResolverFactory);
    createChannel();
    FakeNameResolverFactory.FakeNameResolver resolver = Iterables.getOnlyElement(nameResolverFactory.resolvers);
    assertThat(resolver.refreshCalled).isEqualTo(0);
    ArgumentCaptor<Helper> helperCaptor = ArgumentCaptor.forClass(Helper.class);
    verify(mockLoadBalancerProvider).newLoadBalancer(helperCaptor.capture());
    helper = helperCaptor.getValue();
    SubchannelStateListener listener = new SubchannelStateListener() {

        @Override
        public void onSubchannelState(ConnectivityStateInfo newState) {
            // TRANSIENT_FAILURE or IDLE
            if (newState.getState() == TRANSIENT_FAILURE || newState.getState() == IDLE) {
                helper.refreshNameResolution();
            }
        }
    };
    Subchannel subchannel = createSubchannelSafely(helper, addressGroup, Attributes.EMPTY, listener);
    InternalSubchannel internalSubchannel = (InternalSubchannel) subchannel.getInternalSubchannel();
    internalSubchannel.obtainActiveTransport();
    MockClientTransportInfo transportInfo = transports.poll();
    // Break subchannel connection and simulate load balancer refreshing name resolution
    transportInfo.listener.transportShutdown(Status.UNAVAILABLE.withDescription("unreachable"));
    assertThat(logs).isEmpty();
    assertThat(resolver.refreshCalled).isEqualTo(1);
}
Also used : Helper(io.grpc.LoadBalancer.Helper) SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) ConnectivityStateInfo(io.grpc.ConnectivityStateInfo) EquivalentAddressGroup(io.grpc.EquivalentAddressGroup) ForwardingSubchannel(io.grpc.util.ForwardingSubchannel) Subchannel(io.grpc.LoadBalancer.Subchannel) UnsupportedClientTransportFactoryBuilder(io.grpc.internal.ManagedChannelImplBuilder.UnsupportedClientTransportFactoryBuilder) ClientTransportFactoryBuilder(io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder) MockClientTransportInfo(io.grpc.internal.TestUtils.MockClientTransportInfo) Test(org.junit.Test)

Aggregations

SubchannelStateListener (io.grpc.LoadBalancer.SubchannelStateListener)22 Test (org.junit.Test)19 Subchannel (io.grpc.LoadBalancer.Subchannel)13 InOrder (org.mockito.InOrder)13 Attributes (io.grpc.Attributes)11 ResolvedAddresses (io.grpc.LoadBalancer.ResolvedAddresses)7 CreateSubchannelArgs (io.grpc.LoadBalancer.CreateSubchannelArgs)6 Status (io.grpc.Status)6 SubchannelPicker (io.grpc.LoadBalancer.SubchannelPicker)5 OrcaLoadReport (com.github.xds.data.orca.v3.OrcaLoadReport)4 ConnectivityStateInfo (io.grpc.ConnectivityStateInfo)4 MockClientTransportInfo (io.grpc.internal.TestUtils.MockClientTransportInfo)4 ForwardingSubchannel (io.grpc.util.ForwardingSubchannel)4 EquivalentAddressGroup (io.grpc.EquivalentAddressGroup)3 Helper (io.grpc.LoadBalancer.Helper)3 ProxiedSocketAddress (io.grpc.ProxiedSocketAddress)3 ClientTransportOptions (io.grpc.internal.ClientTransportFactory.ClientTransportOptions)3 SocketAddress (java.net.SocketAddress)3 ChannelLogger (io.grpc.ChannelLogger)2 ClientTransportFactoryBuilder (io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder)2