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();
}
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);
}
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);
}
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());
}
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();
}
Aggregations