Search in sources :

Example 1 with ClientStreamTracer

use of io.grpc.ClientStreamTracer in project grpc-java by grpc.

the class DelayedClientTransportTest method reprocessSemantics.

@Test
public void reprocessSemantics() {
    CallOptions failFastCallOptions = CallOptions.DEFAULT.withOption(SHARD_ID, 1);
    CallOptions waitForReadyCallOptions = CallOptions.DEFAULT.withOption(SHARD_ID, 2).withWaitForReady();
    AbstractSubchannel subchannel1 = mock(AbstractSubchannel.class);
    AbstractSubchannel subchannel2 = mock(AbstractSubchannel.class);
    AbstractSubchannel subchannel3 = mock(AbstractSubchannel.class);
    when(mockRealTransport.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockRealStream);
    when(mockRealTransport2.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockRealStream2);
    when(subchannel1.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport));
    when(subchannel2.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport2));
    when(subchannel3.getInternalSubchannel()).thenReturn(newTransportProvider(null));
    // Fail-fast streams
    DelayedStream ff1 = (DelayedStream) delayedTransport.newStream(method, headers, failFastCallOptions, tracers);
    ff1.start(mock(ClientStreamListener.class));
    ff1.halfClose();
    PickSubchannelArgsImpl ff1args = new PickSubchannelArgsImpl(method, headers, failFastCallOptions);
    verify(transportListener).transportInUse(true);
    DelayedStream ff2 = (DelayedStream) delayedTransport.newStream(method2, headers2, failFastCallOptions, tracers);
    PickSubchannelArgsImpl ff2args = new PickSubchannelArgsImpl(method2, headers2, failFastCallOptions);
    DelayedStream ff3 = (DelayedStream) delayedTransport.newStream(method, headers, failFastCallOptions, tracers);
    PickSubchannelArgsImpl ff3args = new PickSubchannelArgsImpl(method, headers, failFastCallOptions);
    DelayedStream ff4 = (DelayedStream) delayedTransport.newStream(method2, headers2, failFastCallOptions, tracers);
    PickSubchannelArgsImpl ff4args = new PickSubchannelArgsImpl(method2, headers2, failFastCallOptions);
    // Wait-for-ready streams
    FakeClock wfr3Executor = new FakeClock();
    DelayedStream wfr1 = (DelayedStream) delayedTransport.newStream(method, headers, waitForReadyCallOptions, tracers);
    PickSubchannelArgsImpl wfr1args = new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions);
    DelayedStream wfr2 = (DelayedStream) delayedTransport.newStream(method2, headers2, waitForReadyCallOptions, tracers);
    PickSubchannelArgsImpl wfr2args = new PickSubchannelArgsImpl(method2, headers2, waitForReadyCallOptions);
    CallOptions wfr3callOptions = waitForReadyCallOptions.withExecutor(wfr3Executor.getScheduledExecutorService());
    DelayedStream wfr3 = (DelayedStream) delayedTransport.newStream(method, headers, wfr3callOptions, tracers);
    wfr3.start(mock(ClientStreamListener.class));
    wfr3.halfClose();
    PickSubchannelArgsImpl wfr3args = new PickSubchannelArgsImpl(method, headers, wfr3callOptions);
    DelayedStream wfr4 = (DelayedStream) delayedTransport.newStream(method2, headers2, waitForReadyCallOptions, tracers);
    PickSubchannelArgsImpl wfr4args = new PickSubchannelArgsImpl(method2, headers2, waitForReadyCallOptions);
    assertEquals(8, delayedTransport.getPendingStreamsCount());
    // First reprocess(). Some will proceed, some will fail and the rest will stay buffered.
    SubchannelPicker picker = mock(SubchannelPicker.class);
    when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(// ff1: proceed
    PickResult.withSubchannel(subchannel1), // ff2: fail
    PickResult.withError(Status.UNAVAILABLE), // ff3: stay
    PickResult.withSubchannel(subchannel3), // ff4: stay
    PickResult.withNoResult(), // wfr1: proceed
    PickResult.withSubchannel(subchannel2), // wfr2: stay
    PickResult.withError(Status.RESOURCE_EXHAUSTED), // wfr3: stay
    PickResult.withSubchannel(subchannel3));
    InOrder inOrder = inOrder(picker);
    delayedTransport.reprocess(picker);
    assertEquals(5, delayedTransport.getPendingStreamsCount());
    inOrder.verify(picker).pickSubchannel(ff1args);
    inOrder.verify(picker).pickSubchannel(ff2args);
    inOrder.verify(picker).pickSubchannel(ff3args);
    inOrder.verify(picker).pickSubchannel(ff4args);
    inOrder.verify(picker).pickSubchannel(wfr1args);
    inOrder.verify(picker).pickSubchannel(wfr2args);
    inOrder.verify(picker).pickSubchannel(wfr3args);
    inOrder.verify(picker).pickSubchannel(wfr4args);
    inOrder.verifyNoMoreInteractions();
    // Make sure that streams are created and started immediately, not in any executor. This is
    // necessary during shut down to guarantee that when DelayedClientTransport terminates, all
    // streams are now owned by a real transport (which should prevent the Channel from
    // terminating).
    // ff1 and wfr1 went through
    verify(mockRealTransport).newStream(method, headers, failFastCallOptions, tracers);
    verify(mockRealTransport2).newStream(method, headers, waitForReadyCallOptions, tracers);
    assertSame(mockRealStream, ff1.getRealStream());
    assertSame(mockRealStream2, wfr1.getRealStream());
    verify(mockRealStream).start(any(ClientStreamListener.class));
    // But also verify that non-start()-related calls are run within the Executor, since they may be
    // slow.
    verify(mockRealStream, never()).halfClose();
    fakeExecutor.runDueTasks();
    assertEquals(0, fakeExecutor.numPendingTasks());
    verify(mockRealStream).halfClose();
    // The ff2 has failed due to picker returning an error
    assertSame(Status.UNAVAILABLE, ((FailingClientStream) ff2.getRealStream()).getError());
    // Other streams are still buffered
    assertNull(ff3.getRealStream());
    assertNull(ff4.getRealStream());
    assertNull(wfr2.getRealStream());
    assertNull(wfr3.getRealStream());
    assertNull(wfr4.getRealStream());
    // Second reprocess(). All existing streams will proceed.
    picker = mock(SubchannelPicker.class);
    when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(// ff3
    PickResult.withSubchannel(subchannel1), // ff4
    PickResult.withSubchannel(subchannel2), // wfr2
    PickResult.withSubchannel(subchannel2), // wfr3
    PickResult.withSubchannel(subchannel1), // wfr4
    PickResult.withSubchannel(subchannel2), // wfr5 (not yet created)
    PickResult.withNoResult());
    inOrder = inOrder(picker);
    assertEquals(0, wfr3Executor.numPendingTasks());
    verify(transportListener, never()).transportInUse(false);
    delayedTransport.reprocess(picker);
    assertEquals(0, delayedTransport.getPendingStreamsCount());
    verify(transportListener).transportInUse(false);
    // ff3
    inOrder.verify(picker).pickSubchannel(ff3args);
    // ff4
    inOrder.verify(picker).pickSubchannel(ff4args);
    // wfr2
    inOrder.verify(picker).pickSubchannel(wfr2args);
    // wfr3
    inOrder.verify(picker).pickSubchannel(wfr3args);
    // wfr4
    inOrder.verify(picker).pickSubchannel(wfr4args);
    inOrder.verifyNoMoreInteractions();
    fakeExecutor.runDueTasks();
    assertEquals(0, fakeExecutor.numPendingTasks());
    assertSame(mockRealStream, ff3.getRealStream());
    assertSame(mockRealStream2, ff4.getRealStream());
    assertSame(mockRealStream2, wfr2.getRealStream());
    assertSame(mockRealStream2, wfr4.getRealStream());
    assertSame(mockRealStream, wfr3.getRealStream());
    // If there is an executor in the CallOptions, it will be used to create the real stream.
    // 1 for ff1
    verify(mockRealStream, times(1)).halfClose();
    wfr3Executor.runDueTasks();
    verify(mockRealStream, times(2)).halfClose();
    // New streams will use the last picker
    DelayedStream wfr5 = (DelayedStream) delayedTransport.newStream(method, headers, waitForReadyCallOptions, tracers);
    assertNull(wfr5.getRealStream());
    inOrder.verify(picker).pickSubchannel(new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions));
    inOrder.verifyNoMoreInteractions();
    assertEquals(1, delayedTransport.getPendingStreamsCount());
    // wfr5 will stop delayed transport from terminating
    delayedTransport.shutdown(SHUTDOWN_STATUS);
    verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS));
    verify(transportListener, never()).transportTerminated();
    // ... until it's gone
    picker = mock(SubchannelPicker.class);
    when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(PickResult.withSubchannel(subchannel1));
    delayedTransport.reprocess(picker);
    verify(picker).pickSubchannel(new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions));
    fakeExecutor.runDueTasks();
    assertSame(mockRealStream, wfr5.getRealStream());
    assertEquals(0, delayedTransport.getPendingStreamsCount());
    verify(transportListener).transportTerminated();
}
Also used : SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) ClientStreamTracer(io.grpc.ClientStreamTracer) InOrder(org.mockito.InOrder) Metadata(io.grpc.Metadata) PickSubchannelArgs(io.grpc.LoadBalancer.PickSubchannelArgs) CallOptions(io.grpc.CallOptions) MethodDescriptor(io.grpc.MethodDescriptor) Test(org.junit.Test)

Example 2 with ClientStreamTracer

use of io.grpc.ClientStreamTracer in project grpc-java by grpc.

the class RetryTest method statsRecorde_callCancelledBeforeCommit.

@Test
public void statsRecorde_callCancelledBeforeCommit() throws Exception {
    startNewServer();
    retryPolicy = ImmutableMap.<String, Object>builder().put("maxAttempts", 4D).put("initialBackoff", "10s").put("maxBackoff", "10s").put("backoffMultiplier", 1D).put("retryableStatusCodes", Arrays.<Object>asList("UNAVAILABLE")).build();
    createNewChannel();
    // We will have streamClosed return at a particular moment that we want.
    final CountDownLatch streamClosedLatch = new CountDownLatch(1);
    ClientStreamTracer.Factory streamTracerFactory = new ClientStreamTracer.Factory() {

        @Override
        public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
            return new ClientStreamTracer() {

                @Override
                public void streamClosed(Status status) {
                    if (status.getCode().equals(Code.CANCELLED)) {
                        try {
                            streamClosedLatch.await();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            throw new AssertionError("streamClosedLatch interrupted", e);
                        }
                    }
                }
            };
        }
    };
    ClientCall<String, Integer> call = channel.newCall(clientStreamingMethod, CallOptions.DEFAULT.withStreamTracerFactory(streamTracerFactory));
    call.start(mockCallListener, new Metadata());
    assertRpcStartedRecorded();
    fakeClock.forwardTime(5, SECONDS);
    String message = "String of length 20.";
    call.sendMessage(message);
    assertOutboundMessageRecorded();
    ServerCall<String, Integer> serverCall = serverCalls.poll(5, SECONDS);
    serverCall.request(2);
    assertOutboundWireSizeRecorded(message.length());
    // trigger retry
    serverCall.close(Status.UNAVAILABLE.withDescription("original attempt failed"), new Metadata());
    assertRpcStatusRecorded(Code.UNAVAILABLE, 5000, 1);
    elapseBackoff(10, SECONDS);
    assertRpcStartedRecorded();
    assertOutboundMessageRecorded();
    serverCall = serverCalls.poll(5, SECONDS);
    serverCall.request(2);
    assertOutboundWireSizeRecorded(message.length());
    fakeClock.forwardTime(7, SECONDS);
    // A noop substream will commit.
    call.cancel("Cancelled before commit", null);
    // The call listener is closed, but the netty substream listener is not yet closed.
    verify(mockCallListener, timeout(5000)).onClose(any(Status.class), any(Metadata.class));
    // Let the netty substream listener be closed.
    streamClosedLatch.countDown();
    assertRetryStatsRecorded(1, 0, 10_000);
    assertRpcStatusRecorded(Code.CANCELLED, 7_000, 1);
}
Also used : Status(io.grpc.Status) ClientStreamTracer(io.grpc.ClientStreamTracer) Metadata(io.grpc.Metadata) CountDownLatch(java.util.concurrent.CountDownLatch) StreamInfo(io.grpc.ClientStreamTracer.StreamInfo) Test(org.junit.Test)

Example 3 with ClientStreamTracer

use of io.grpc.ClientStreamTracer in project grpc-java by grpc.

the class RetriableStreamTest method hedging_perRpcBufferLimitExceeded.

@Test
public void hedging_perRpcBufferLimitExceeded() {
    ClientStream mockStream1 = mock(ClientStream.class);
    ClientStream mockStream2 = mock(ClientStream.class);
    doReturn(mockStream1).when(retriableStreamRecorder).newSubstream(0);
    doReturn(mockStream2).when(retriableStreamRecorder).newSubstream(1);
    hedgingStream.start(masterListener);
    ArgumentCaptor<ClientStreamListener> sublistenerCaptor1 = ArgumentCaptor.forClass(ClientStreamListener.class);
    verify(mockStream1).start(sublistenerCaptor1.capture());
    verify(mockStream1).isReady();
    ClientStreamTracer bufferSizeTracer1 = bufferSizeTracer;
    bufferSizeTracer1.outboundWireSize(PER_RPC_BUFFER_LIMIT - 1);
    fakeClock.forwardTime(HEDGING_DELAY_IN_SECONDS, TimeUnit.SECONDS);
    ArgumentCaptor<ClientStreamListener> sublistenerCaptor2 = ArgumentCaptor.forClass(ClientStreamListener.class);
    verify(mockStream2).start(sublistenerCaptor2.capture());
    verify(mockStream1, times(2)).isReady();
    verify(mockStream2).isReady();
    ClientStreamTracer bufferSizeTracer2 = bufferSizeTracer;
    bufferSizeTracer2.outboundWireSize(PER_RPC_BUFFER_LIMIT - 1);
    verify(retriableStreamRecorder, never()).postCommit();
    // bufferLimitExceeded
    bufferSizeTracer2.outboundWireSize(2);
    ArgumentCaptor<Status> statusCaptor = ArgumentCaptor.forClass(Status.class);
    verify(mockStream1).cancel(statusCaptor.capture());
    assertEquals(Status.CANCELLED.getCode(), statusCaptor.getValue().getCode());
    assertEquals(CANCELLED_BECAUSE_COMMITTED, statusCaptor.getValue().getDescription());
    verify(retriableStreamRecorder).postCommit();
    verifyNoMoreInteractions(mockStream1);
    verify(mockStream2).isReady();
    verifyNoMoreInteractions(mockStream2);
}
Also used : Status(io.grpc.Status) ClientStreamTracer(io.grpc.ClientStreamTracer) Test(org.junit.Test)

Example 4 with ClientStreamTracer

use of io.grpc.ClientStreamTracer in project grpc-java by grpc.

the class OrcaPerRequestUtilTest method singlePolicyTypicalWorkflow.

/**
 * Tests a single load balance policy's listener receive per-request ORCA reports upon call
 * trailer arrives.
 */
@Test
public void singlePolicyTypicalWorkflow() {
    // Use a mocked noop stream tracer factory as the original stream tracer factory.
    ClientStreamTracer.Factory fakeDelegateFactory = mock(ClientStreamTracer.Factory.class);
    ClientStreamTracer fakeTracer = mock(ClientStreamTracer.class);
    doNothing().when(fakeTracer).inboundTrailers(any(Metadata.class));
    when(fakeDelegateFactory.newClientStreamTracer(any(ClientStreamTracer.StreamInfo.class), any(Metadata.class))).thenReturn(fakeTracer);
    // The OrcaReportingTracerFactory will augment the StreamInfo passed to its
    // newClientStreamTracer method. The augmented StreamInfo's CallOptions will contain
    // a OrcaReportBroker, in which has the registered listener.
    ClientStreamTracer.Factory factory = OrcaPerRequestUtil.getInstance().newOrcaClientStreamTracerFactory(fakeDelegateFactory, orcaListener1);
    ClientStreamTracer tracer = factory.newClientStreamTracer(STREAM_INFO, new Metadata());
    ArgumentCaptor<ClientStreamTracer.StreamInfo> streamInfoCaptor = ArgumentCaptor.forClass(null);
    verify(fakeDelegateFactory).newClientStreamTracer(streamInfoCaptor.capture(), any(Metadata.class));
    ClientStreamTracer.StreamInfo capturedInfo = streamInfoCaptor.getValue();
    assertThat(capturedInfo).isNotEqualTo(STREAM_INFO);
    // When the trailer does not contain ORCA report, listener callback will not be invoked.
    Metadata trailer = new Metadata();
    tracer.inboundTrailers(trailer);
    verifyNoMoreInteractions(orcaListener1);
    // When the trailer contains an ORCA report, listener callback will be invoked.
    trailer.put(OrcaReportingTracerFactory.ORCA_ENDPOINT_LOAD_METRICS_KEY, OrcaLoadReport.getDefaultInstance());
    tracer.inboundTrailers(trailer);
    ArgumentCaptor<OrcaLoadReport> reportCaptor = ArgumentCaptor.forClass(null);
    verify(orcaListener1).onLoadReport(reportCaptor.capture());
    assertThat(reportCaptor.getValue()).isEqualTo(OrcaLoadReport.getDefaultInstance());
}
Also used : ClientStreamTracer(io.grpc.ClientStreamTracer) Metadata(io.grpc.Metadata) OrcaLoadReport(com.github.xds.data.orca.v3.OrcaLoadReport) Test(org.junit.Test)

Example 5 with ClientStreamTracer

use of io.grpc.ClientStreamTracer in project grpc-java by grpc.

the class ClusterImplLoadBalancerTest method recordLoadStats.

@Test
public void recordLoadStats() {
    LoadBalancerProvider weightedTargetProvider = new WeightedTargetLoadBalancerProvider();
    WeightedTargetConfig weightedTargetConfig = buildWeightedTargetConfig(ImmutableMap.of(locality, 10));
    ClusterImplConfig config = new ClusterImplConfig(CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_INFO, null, Collections.<DropOverload>emptyList(), new PolicySelection(weightedTargetProvider, weightedTargetConfig), null);
    EquivalentAddressGroup endpoint = makeAddress("endpoint-addr", locality);
    deliverAddressesAndConfig(Collections.singletonList(endpoint), config);
    FakeLoadBalancer leafBalancer = Iterables.getOnlyElement(downstreamBalancers);
    Subchannel subchannel = leafBalancer.helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(leafBalancer.addresses).build());
    leafBalancer.deliverSubchannelState(subchannel, ConnectivityState.READY);
    assertThat(currentState).isEqualTo(ConnectivityState.READY);
    PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
    assertThat(result.getStatus().isOk()).isTrue();
    ClientStreamTracer streamTracer1 = result.getStreamTracerFactory().newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), // first RPC call
    new Metadata());
    ClientStreamTracer streamTracer2 = result.getStreamTracerFactory().newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), // second RPC call
    new Metadata());
    ClientStreamTracer streamTracer3 = result.getStreamTracerFactory().newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), // third RPC call
    new Metadata());
    streamTracer1.streamClosed(Status.OK);
    streamTracer2.streamClosed(Status.UNAVAILABLE);
    ClusterStats clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
    UpstreamLocalityStats localityStats = Iterables.getOnlyElement(clusterStats.upstreamLocalityStatsList());
    assertThat(localityStats.locality()).isEqualTo(locality);
    assertThat(localityStats.totalIssuedRequests()).isEqualTo(3L);
    assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
    assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
    assertThat(localityStats.totalRequestsInProgress()).isEqualTo(1L);
    streamTracer3.streamClosed(Status.OK);
    // stats recorder released
    subchannel.shutdown();
    clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
    // Locality load is reported for one last time in case of loads occurred since the previous
    // load report.
    localityStats = Iterables.getOnlyElement(clusterStats.upstreamLocalityStatsList());
    assertThat(localityStats.locality()).isEqualTo(locality);
    assertThat(localityStats.totalIssuedRequests()).isEqualTo(0L);
    assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
    assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
    assertThat(localityStats.totalRequestsInProgress()).isEqualTo(0L);
    clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
    // no longer reported
    assertThat(clusterStats.upstreamLocalityStatsList()).isEmpty();
}
Also used : UpstreamLocalityStats(io.grpc.xds.Stats.UpstreamLocalityStats) ClientStreamTracer(io.grpc.ClientStreamTracer) Metadata(io.grpc.Metadata) WeightedTargetConfig(io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedTargetConfig) WeightedPolicySelection(io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedPolicySelection) PolicySelection(io.grpc.internal.ServiceConfigUtil.PolicySelection) ClusterImplConfig(io.grpc.xds.ClusterImplLoadBalancerProvider.ClusterImplConfig) ClusterStats(io.grpc.xds.Stats.ClusterStats) EquivalentAddressGroup(io.grpc.EquivalentAddressGroup) Subchannel(io.grpc.LoadBalancer.Subchannel) LoadBalancerProvider(io.grpc.LoadBalancerProvider) PickResult(io.grpc.LoadBalancer.PickResult) PickSubchannelArgs(io.grpc.LoadBalancer.PickSubchannelArgs) Test(org.junit.Test)

Aggregations

ClientStreamTracer (io.grpc.ClientStreamTracer)57 Metadata (io.grpc.Metadata)54 Test (org.junit.Test)44 CallOptions (io.grpc.CallOptions)28 Subchannel (io.grpc.LoadBalancer.Subchannel)22 MockClientTransportInfo (io.grpc.internal.TestUtils.MockClientTransportInfo)21 PickSubchannelArgs (io.grpc.LoadBalancer.PickSubchannelArgs)19 ForwardingSubchannel (io.grpc.util.ForwardingSubchannel)18 MethodDescriptor (io.grpc.MethodDescriptor)16 Status (io.grpc.Status)14 ChannelLogger (io.grpc.ChannelLogger)11 ClientTransportOptions (io.grpc.internal.ClientTransportFactory.ClientTransportOptions)10 ProxiedSocketAddress (io.grpc.ProxiedSocketAddress)9 StreamInfo (io.grpc.ClientStreamTracer.StreamInfo)8 CallAttemptsTracerFactory (io.grpc.census.CensusTracingModule.CallAttemptsTracerFactory)8 SocketAddress (java.net.SocketAddress)8 EquivalentAddressGroup (io.grpc.EquivalentAddressGroup)7 Helper (io.grpc.LoadBalancer.Helper)7 SubchannelPicker (io.grpc.LoadBalancer.SubchannelPicker)7 ManagedChannel (io.grpc.ManagedChannel)7