Search in sources :

Example 21 with ResolvedAddresses

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

the class HealthCheckingLoadBalancerFactoryTest method serverRespondResetsBackoff.

@Test
public void serverRespondResetsBackoff() {
    Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
    ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result);
    verify(origLb).handleResolvedAddresses(result);
    verifyNoMoreInteractions(origLb);
    SubchannelStateListener mockStateListener = mockStateListeners[0];
    Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
    assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[0]);
    InOrder inOrder = inOrder(mockStateListener, backoffPolicyProvider, backoffPolicy1, backoffPolicy2);
    deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
    inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    HealthImpl healthImpl = healthImpls[0];
    assertThat(healthImpl.calls).hasSize(1);
    assertThat(clock.getPendingTasks()).isEmpty();
    // Server closes the health checking RPC without any response
    healthImpl.calls.poll().responseObserver.onError(Status.CANCELLED.asException());
    // which results in TRANSIENT_FAILURE
    inOrder.verify(mockStateListener).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.CANCELLED + " for 'TeeService'"));
    // Retry with backoff is scheduled
    inOrder.verify(backoffPolicyProvider).get();
    inOrder.verify(backoffPolicy1).nextBackoffNanos();
    assertThat(clock.getPendingTasks()).hasSize(1);
    verifyRetryAfterNanos(inOrder, mockStateListener, healthImpl, 11);
    assertThat(clock.getPendingTasks()).isEmpty();
    // Server responds
    healthImpl.calls.peek().responseObserver.onNext(makeResponse(ServingStatus.SERVING));
    inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
    verifyNoMoreInteractions(mockStateListener);
    // then closes the stream
    healthImpl.calls.poll().responseObserver.onError(Status.UNAVAILABLE.asException());
    inOrder.verify(mockStateListener).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.UNAVAILABLE + " for 'TeeService'"));
    // Because server has responded, the first retry is not subject to backoff.
    // But the backoff policy has been reset.  A new backoff policy will be used for
    // the next backed-off retry.
    inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    assertThat(healthImpl.calls).hasSize(1);
    assertThat(clock.getPendingTasks()).isEmpty();
    inOrder.verifyNoMoreInteractions();
    // then closes the stream for this retry
    healthImpl.calls.poll().responseObserver.onError(Status.UNAVAILABLE.asException());
    inOrder.verify(mockStateListener).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.UNAVAILABLE + " for 'TeeService'"));
    // New backoff policy is used
    inOrder.verify(backoffPolicyProvider).get();
    // Retry with a new backoff policy
    inOrder.verify(backoffPolicy2).nextBackoffNanos();
    verifyRetryAfterNanos(inOrder, mockStateListener, healthImpl, 12);
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) InOrder(org.mockito.InOrder) Subchannel(io.grpc.LoadBalancer.Subchannel) Attributes(io.grpc.Attributes) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 22 with ResolvedAddresses

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

the class HealthCheckingLoadBalancerFactoryTest method healthCheckDisabledWhenServiceNotImplemented.

@Test
public void healthCheckDisabledWhenServiceNotImplemented() {
    Attributes resolutionAttrs = attrsWithHealthCheckService("BarService");
    ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result);
    verify(origLb).handleResolvedAddresses(result);
    verifyNoMoreInteractions(origLb);
    // We create 2 Subchannels. One of them connects to a server that doesn't implement health check
    for (int i = 0; i < 2; i++) {
        createSubchannel(i, Attributes.EMPTY);
    }
    InOrder inOrder = inOrder(mockStateListeners[0], mockStateListeners[1]);
    for (int i = 0; i < 2; i++) {
        deliverSubchannelState(i, ConnectivityStateInfo.forNonError(READY));
        assertThat(healthImpls[i].calls).hasSize(1);
        inOrder.verify(mockStateListeners[i]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    }
    ServerSideCall serverCall0 = healthImpls[0].calls.poll();
    ServerSideCall serverCall1 = healthImpls[1].calls.poll();
    subchannels[0].logs.clear();
    // subchannels[0] gets UNIMPLEMENTED for health checking, which will disable health
    // checking and it'll use the original state, which is currently READY.
    // In reality UNIMPLEMENTED is generated by GRPC server library, but the client can't tell
    // whether it's the server library or the service implementation that returned this status.
    serverCall0.responseObserver.onError(Status.UNIMPLEMENTED.asException());
    inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
    assertThat(subchannels[0].logs).containsExactly("ERROR: Health-check disabled: " + Status.UNIMPLEMENTED, "INFO: READY (no health-check)").inOrder();
    // subchannels[1] has normal health checking
    serverCall1.responseObserver.onNext(makeResponse(ServingStatus.NOT_SERVING));
    inOrder.verify(mockStateListeners[1]).onSubchannelState(unavailableStateWithMsg("Health-check service responded NOT_SERVING for 'BarService'"));
    // Without health checking, states from underlying Subchannel are delivered directly to the mock
    // listeners.
    deliverSubchannelState(0, ConnectivityStateInfo.forNonError(IDLE));
    inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(IDLE)));
    // Re-connecting on a Subchannel will reset the "disabled" flag.
    assertThat(healthImpls[0].calls).hasSize(0);
    deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
    assertThat(healthImpls[0].calls).hasSize(1);
    serverCall0 = healthImpls[0].calls.poll();
    inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    // Health check now works as normal
    serverCall0.responseObserver.onNext(makeResponse(ServingStatus.SERVICE_UNKNOWN));
    inOrder.verify(mockStateListeners[0]).onSubchannelState(unavailableStateWithMsg("Health-check service responded SERVICE_UNKNOWN for 'BarService'"));
    verifyNoMoreInteractions(origLb, mockStateListeners[0], mockStateListeners[1]);
    verifyNoInteractions(backoffPolicyProvider);
}
Also used : InOrder(org.mockito.InOrder) Attributes(io.grpc.Attributes) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 23 with ResolvedAddresses

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

the class HealthCheckingLoadBalancerFactoryTest method typicalWorkflow.

@Test
public void typicalWorkflow() {
    Attributes resolutionAttrs = attrsWithHealthCheckService("FooService");
    ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result);
    verify(origLb).handleResolvedAddresses(result);
    verify(origHelper, atLeast(0)).getSynchronizationContext();
    verify(origHelper, atLeast(0)).getScheduledExecutorService();
    verifyNoMoreInteractions(origHelper);
    verifyNoMoreInteractions(origLb);
    Subchannel[] wrappedSubchannels = new Subchannel[NUM_SUBCHANNELS];
    // Simulate that the orignal LB creates Subchannels
    for (int i = 0; i < NUM_SUBCHANNELS; i++) {
        // Subchannel attributes set by origLb are correctly plumbed in
        String subchannelAttrValue = "eag attr " + i;
        Attributes attrs = Attributes.newBuilder().set(SUBCHANNEL_ATTR_KEY, subchannelAttrValue).build();
        wrappedSubchannels[i] = createSubchannel(i, attrs);
        assertThat(unwrap(wrappedSubchannels[i])).isSameInstanceAs(subchannels[i]);
        verify(origHelper, times(i + 1)).createSubchannel(createArgsCaptor.capture());
        assertThat(createArgsCaptor.getValue().getAddresses()).isEqualTo(eagLists[i]);
        assertThat(createArgsCaptor.getValue().getAttributes().get(SUBCHANNEL_ATTR_KEY)).isEqualTo(subchannelAttrValue);
    }
    for (int i = NUM_SUBCHANNELS - 1; i >= 0; i--) {
        // Not starting health check until underlying Subchannel is READY
        FakeSubchannel subchannel = subchannels[i];
        HealthImpl healthImpl = healthImpls[i];
        SubchannelStateListener mockStateListener = mockStateListeners[i];
        InOrder inOrder = inOrder(mockStateListener);
        deliverSubchannelState(i, ConnectivityStateInfo.forNonError(CONNECTING));
        deliverSubchannelState(i, ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE));
        deliverSubchannelState(i, ConnectivityStateInfo.forNonError(IDLE));
        inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
        inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE)));
        inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(IDLE)));
        verifyNoMoreInteractions(mockStateListener);
        assertThat(subchannel.logs).isEmpty();
        assertThat(healthImpl.calls).isEmpty();
        deliverSubchannelState(i, ConnectivityStateInfo.forNonError(READY));
        assertThat(healthImpl.calls).hasSize(1);
        ServerSideCall serverCall = healthImpl.calls.peek();
        assertThat(serverCall.request).isEqualTo(makeRequest("FooService"));
        // Starting the health check will make the Subchannel appear CONNECTING to the origLb.
        inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
        verifyNoMoreInteractions(mockStateListener);
        assertThat(subchannel.logs).containsExactly("INFO: CONNECTING: Starting health-check for \"FooService\"");
        subchannel.logs.clear();
        // Simulate a series of responses.
        for (ServingStatus servingStatus : new ServingStatus[] { ServingStatus.UNKNOWN, ServingStatus.NOT_SERVING, ServingStatus.SERVICE_UNKNOWN, ServingStatus.SERVING, ServingStatus.NOT_SERVING, ServingStatus.SERVING }) {
            serverCall.responseObserver.onNext(makeResponse(servingStatus));
            // SERVING is mapped to READY, while other statuses are mapped to TRANSIENT_FAILURE
            if (servingStatus == ServingStatus.SERVING) {
                inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
                assertThat(subchannel.logs).containsExactly("INFO: READY: health-check responded SERVING");
            } else {
                inOrder.verify(mockStateListener).onSubchannelState(unavailableStateWithMsg("Health-check service responded " + servingStatus + " for 'FooService'"));
                assertThat(subchannel.logs).containsExactly("INFO: TRANSIENT_FAILURE: health-check responded " + servingStatus);
            }
            subchannel.logs.clear();
            verifyNoMoreInteractions(mockStateListener);
        }
    }
    // origLb shuts down Subchannels
    for (int i = 0; i < NUM_SUBCHANNELS; i++) {
        FakeSubchannel subchannel = subchannels[i];
        SubchannelStateListener mockStateListener = mockStateListeners[i];
        ServerSideCall serverCall = healthImpls[i].calls.peek();
        assertThat(serverCall.cancelled).isFalse();
        verifyNoMoreInteractions(mockStateListener);
        assertThat(subchannels[i].isShutdown).isFalse();
        final Subchannel wrappedSubchannel = wrappedSubchannels[i];
        // Subchannel enters SHUTDOWN state as a response to shutdown(), and that will cancel the
        // health check RPC
        syncContext.execute(new Runnable() {

            @Override
            public void run() {
                wrappedSubchannel.shutdown();
            }
        });
        assertThat(subchannels[i].isShutdown).isTrue();
        assertThat(serverCall.cancelled).isTrue();
        verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(SHUTDOWN)));
        assertThat(subchannel.logs).isEmpty();
    }
    for (int i = 0; i < NUM_SUBCHANNELS; i++) {
        assertThat(healthImpls[i].calls).hasSize(1);
    }
    verifyNoInteractions(backoffPolicyProvider);
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) InOrder(org.mockito.InOrder) Attributes(io.grpc.Attributes) ServingStatus(io.grpc.health.v1.HealthCheckResponse.ServingStatus) Subchannel(io.grpc.LoadBalancer.Subchannel) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 24 with ResolvedAddresses

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

the class HealthCheckingLoadBalancerFactoryTest method serviceConfigChangesServiceNameWhenRetryPending.

@Test
public void serviceConfigChangesServiceNameWhenRetryPending() {
    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);
    deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
    inOrder.verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    HealthImpl healthImpl = healthImpls[0];
    assertThat(healthImpl.calls).hasSize(1);
    ServerSideCall serverCall = healthImpl.calls.poll();
    assertThat(serverCall.cancelled).isFalse();
    assertThat(serverCall.request).isEqualTo(makeRequest("TeeService"));
    // Health check stream closed without responding.  Client in retry backoff.
    assertThat(clock.getPendingTasks()).isEmpty();
    serverCall.responseObserver.onCompleted();
    assertThat(clock.getPendingTasks()).hasSize(1);
    assertThat(healthImpl.calls).isEmpty();
    inOrder.verify(mockListener).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.OK + " for 'TeeService'"));
    // 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);
    verifyNoMoreInteractions(origLb, mockListener);
    assertThat(clock.getPendingTasks()).hasSize(1);
    assertThat(healthImpl.calls).isEmpty();
    // Service config returns a different health check name.
    resolutionAttrs = attrsWithHealthCheckService("FooService");
    ResolvedAddresses result2 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result2);
    // Concluded CONNECTING state
    inOrder.verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
    inOrder.verify(origLb).handleResolvedAddresses(result2);
    // Current retry timer cancelled
    assertThat(clock.getPendingTasks()).isEmpty();
    // A second RPC is started immediately
    assertThat(healthImpl.calls).hasSize(1);
    serverCall = healthImpl.calls.poll();
    // with the new service name
    assertThat(serverCall.request).isEqualTo(makeRequest("FooService"));
    verifyNoMoreInteractions(origLb, mockListener);
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) InOrder(org.mockito.InOrder) Subchannel(io.grpc.LoadBalancer.Subchannel) Attributes(io.grpc.Attributes) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Example 25 with ResolvedAddresses

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

the class HealthCheckingLoadBalancerFactoryTest method util_newHealthCheckingLoadBalancer.

@Test
public void util_newHealthCheckingLoadBalancer() {
    LoadBalancer.Factory hcFactory = new LoadBalancer.Factory() {

        @Override
        public LoadBalancer newLoadBalancer(Helper helper) {
            return HealthCheckingLoadBalancerUtil.newHealthCheckingLoadBalancer(origLbFactory, helper);
        }
    };
    // hcLb and wrappedHelper are already set in setUp().  For this special test case, we
    // clear wrappedHelper so that we can create hcLb again with the util.
    wrappedHelper = null;
    hcLb = hcFactory.newLoadBalancer(origHelper);
    // Verify that HC works
    Attributes resolutionAttrs = attrsWithHealthCheckService("BarService");
    ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
    hcLbEventDelivery.handleResolvedAddresses(result);
    verify(origLb).handleResolvedAddresses(result);
    createSubchannel(0, Attributes.EMPTY);
    assertThat(healthImpls[0].calls).isEmpty();
    deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
    assertThat(healthImpls[0].calls).hasSize(1);
}
Also used : Helper(io.grpc.LoadBalancer.Helper) Attributes(io.grpc.Attributes) LoadBalancer(io.grpc.LoadBalancer) ResolvedAddresses(io.grpc.LoadBalancer.ResolvedAddresses) Test(org.junit.Test)

Aggregations

ResolvedAddresses (io.grpc.LoadBalancer.ResolvedAddresses)32 Test (org.junit.Test)31 Attributes (io.grpc.Attributes)16 Status (io.grpc.Status)12 InOrder (org.mockito.InOrder)10 EquivalentAddressGroup (io.grpc.EquivalentAddressGroup)9 Subchannel (io.grpc.LoadBalancer.Subchannel)9 UnsupportedClientTransportFactoryBuilder (io.grpc.internal.ManagedChannelImplBuilder.UnsupportedClientTransportFactoryBuilder)9 Helper (io.grpc.LoadBalancer.Helper)8 SubchannelStateListener (io.grpc.LoadBalancer.SubchannelStateListener)8 LoadBalancer (io.grpc.LoadBalancer)4 ConfigOrError (io.grpc.NameResolver.ConfigOrError)3 AutoConfiguredLoadBalancer (io.grpc.internal.AutoConfiguredLoadBalancerFactory.AutoConfiguredLoadBalancer)3 PolicySelection (io.grpc.internal.ServiceConfigUtil.PolicySelection)3 ForwardingLoadBalancerHelper (io.grpc.util.ForwardingLoadBalancerHelper)3 InetSocketAddress (java.net.InetSocketAddress)3 ConnectivityStateInfo (io.grpc.ConnectivityStateInfo)2 InternalConfigSelector (io.grpc.InternalConfigSelector)2 ServingStatus (io.grpc.health.v1.HealthCheckResponse.ServingStatus)2 SocketAddress (java.net.SocketAddress)2