use of io.grpc.ClientStreamTracer in project grpc-java by grpc.
the class CensusModulesTest method traceHeadersPropagateSpanContext.
@Test
public void traceHeadersPropagateSpanContext() throws Exception {
CallAttemptsTracerFactory callTracer = censusTracing.newClientCallTracer(fakeClientParentSpan, method);
Metadata headers = new Metadata();
ClientStreamTracer streamTracer = callTracer.newClientStreamTracer(STREAM_INFO, headers);
streamTracer.streamCreated(Attributes.EMPTY, headers);
verify(mockTracingPropagationHandler).toByteArray(same(fakeAttemptSpanContext));
verifyNoMoreInteractions(mockTracingPropagationHandler);
verify(tracer).spanBuilderWithExplicitParent(eq("Sent.package1.service2.method3"), same(fakeClientParentSpan));
verify(tracer).spanBuilderWithExplicitParent(eq("Attempt.package1.service2.method3"), same(spyClientSpan));
verify(spyClientSpanBuilder).setRecordEvents(eq(true));
verifyNoMoreInteractions(tracer);
assertTrue(headers.containsKey(censusTracing.tracingHeader));
ServerStreamTracer serverTracer = censusTracing.getServerTracerFactory().newServerStreamTracer(method.getFullMethodName(), headers);
verify(mockTracingPropagationHandler).fromByteArray(same(binarySpanContext));
verify(tracer).spanBuilderWithRemoteParent(eq("Recv.package1.service2.method3"), same(spyAttemptSpan.getContext()));
verify(spyServerSpanBuilder).setRecordEvents(eq(true));
Context filteredContext = serverTracer.filterContext(Context.ROOT);
assertSame(spyServerSpan, ContextUtils.getValue(filteredContext));
}
use of io.grpc.ClientStreamTracer in project grpc-java by grpc.
the class CensusModulesTest method recordRetryStats.
// This test is only unit-testing the stat recording logic. The retry behavior is faked.
@Test
public void recordRetryStats() {
CensusStatsModule localCensusStats = new CensusStatsModule(tagger, tagCtxSerializer, statsRecorder, fakeClock.getStopwatchSupplier(), true, true, true, true, true);
CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory = new CensusStatsModule.CallAttemptsTracerFactory(localCensusStats, tagger.empty(), method.getFullMethodName());
ClientStreamTracer tracer = callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, new Metadata());
StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord();
assertEquals(1, record.tags.size());
TagValue methodTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), methodTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_STARTED_COUNT));
fakeClock.forwardTime(30, MILLISECONDS);
tracer.outboundHeaders();
fakeClock.forwardTime(100, MILLISECONDS);
tracer.outboundMessage(0);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_MESSAGES_PER_METHOD, 1, true, true);
tracer.outboundMessage(1);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_MESSAGES_PER_METHOD, 1, true, true);
tracer.outboundWireSize(1028);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_BYTES_PER_METHOD, 1028, true, true);
tracer.outboundUncompressedSize(1128);
fakeClock.forwardTime(24, MILLISECONDS);
tracer.streamClosed(Status.UNAVAILABLE);
record = statsRecorder.pollRecord();
methodTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), methodTag.asString());
TagValue statusTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_STATUS);
assertEquals(Status.Code.UNAVAILABLE.toString(), statusTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_FINISHED_COUNT));
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_ERROR_COUNT));
assertEquals(2, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_COUNT));
assertEquals(1028, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_BYTES));
assertEquals(1128, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_UNCOMPRESSED_REQUEST_BYTES));
assertEquals(30 + 100 + 24, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_ROUNDTRIP_LATENCY));
// faking retry
fakeClock.forwardTime(1000, MILLISECONDS);
tracer = callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, new Metadata());
record = statsRecorder.pollRecord();
assertEquals(1, record.tags.size());
methodTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), methodTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_STARTED_COUNT));
tracer.outboundHeaders();
tracer.outboundMessage(0);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_MESSAGES_PER_METHOD, 1, true, true);
tracer.outboundMessage(1);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_MESSAGES_PER_METHOD, 1, true, true);
tracer.outboundWireSize(1028);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_BYTES_PER_METHOD, 1028, true, true);
tracer.outboundUncompressedSize(1128);
fakeClock.forwardTime(100, MILLISECONDS);
tracer.streamClosed(Status.NOT_FOUND);
record = statsRecorder.pollRecord();
methodTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), methodTag.asString());
statusTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_STATUS);
assertEquals(Status.Code.NOT_FOUND.toString(), statusTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_FINISHED_COUNT));
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_ERROR_COUNT));
assertEquals(2, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_COUNT));
assertEquals(1028, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_BYTES));
assertEquals(1128, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_UNCOMPRESSED_REQUEST_BYTES));
assertEquals(100, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_ROUNDTRIP_LATENCY));
// fake transparent retry
fakeClock.forwardTime(10, MILLISECONDS);
tracer = callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO.toBuilder().setIsTransparentRetry(true).build(), new Metadata());
record = statsRecorder.pollRecord();
assertEquals(1, record.tags.size());
methodTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), methodTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_STARTED_COUNT));
tracer.streamClosed(Status.UNAVAILABLE);
record = statsRecorder.pollRecord();
statusTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_STATUS);
assertEquals(Status.Code.UNAVAILABLE.toString(), statusTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_FINISHED_COUNT));
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_ERROR_COUNT));
assertEquals(0, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_COUNT));
assertEquals(0, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_BYTES));
// fake another transparent retry
fakeClock.forwardTime(10, MILLISECONDS);
tracer = callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO.toBuilder().setIsTransparentRetry(true).build(), new Metadata());
record = statsRecorder.pollRecord();
assertEquals(1, record.tags.size());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_STARTED_COUNT));
tracer.outboundHeaders();
tracer.outboundMessage(0);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_MESSAGES_PER_METHOD, 1, true, true);
tracer.outboundMessage(1);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_MESSAGES_PER_METHOD, 1, true, true);
tracer.outboundWireSize(1028);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_SENT_BYTES_PER_METHOD, 1028, true, true);
tracer.outboundUncompressedSize(1128);
fakeClock.forwardTime(16, MILLISECONDS);
tracer.inboundMessage(0);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_RECEIVED_MESSAGES_PER_METHOD, 1, true, true);
tracer.inboundWireSize(33);
assertRealTimeMetric(RpcMeasureConstants.GRPC_CLIENT_RECEIVED_BYTES_PER_METHOD, 33, true, true);
tracer.inboundUncompressedSize(67);
fakeClock.forwardTime(24, MILLISECONDS);
// RPC succeeded
tracer.streamClosed(Status.OK);
callAttemptsTracerFactory.callEnded(Status.OK);
record = statsRecorder.pollRecord();
statusTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_STATUS);
assertEquals(Status.Code.OK.toString(), statusTag.asString());
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_FINISHED_COUNT));
assertThat(record.getMetric(DeprecatedCensusConstants.RPC_CLIENT_ERROR_COUNT)).isNull();
assertEquals(2, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_COUNT));
assertEquals(1028, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_REQUEST_BYTES));
assertEquals(1128, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_UNCOMPRESSED_REQUEST_BYTES));
assertEquals(1, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_RESPONSE_COUNT));
assertEquals(33, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_RESPONSE_BYTES));
assertEquals(67, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_UNCOMPRESSED_RESPONSE_BYTES));
assertEquals(16 + 24, record.getMetricAsLongOrFail(DeprecatedCensusConstants.RPC_CLIENT_ROUNDTRIP_LATENCY));
record = statsRecorder.pollRecord();
methodTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), methodTag.asString());
statusTag = record.tags.get(RpcMeasureConstants.GRPC_CLIENT_STATUS);
assertEquals(Status.Code.OK.toString(), statusTag.asString());
assertThat(record.getMetric(RETRIES_PER_CALL)).isEqualTo(1);
assertThat(record.getMetric(TRANSPARENT_RETRIES_PER_CALL)).isEqualTo(2);
assertThat(record.getMetric(RETRY_DELAY_PER_CALL)).isEqualTo(1000D + 10 + 10);
}
use of io.grpc.ClientStreamTracer in project grpc-java by grpc.
the class CensusModulesTest method clientBasicTracingDefaultSpan.
@Test
public void clientBasicTracingDefaultSpan() {
CallAttemptsTracerFactory callTracer = censusTracing.newClientCallTracer(null, method);
Metadata headers = new Metadata();
ClientStreamTracer clientStreamTracer = callTracer.newClientStreamTracer(STREAM_INFO, headers);
clientStreamTracer.streamCreated(Attributes.EMPTY, headers);
verify(tracer).spanBuilderWithExplicitParent(eq("Sent.package1.service2.method3"), ArgumentMatchers.<Span>isNull());
verify(tracer).spanBuilderWithExplicitParent(eq("Attempt.package1.service2.method3"), eq(spyClientSpan));
verify(spyClientSpan, never()).end(any(EndSpanOptions.class));
verify(spyAttemptSpan, never()).end(any(EndSpanOptions.class));
clientStreamTracer.outboundMessage(0);
clientStreamTracer.outboundMessageSent(0, 882, -1);
clientStreamTracer.inboundMessage(0);
clientStreamTracer.outboundMessage(1);
clientStreamTracer.outboundMessageSent(1, -1, 27);
clientStreamTracer.inboundMessageRead(0, 255, 90);
clientStreamTracer.streamClosed(Status.OK);
callTracer.callEnded(Status.OK);
InOrder inOrder = inOrder(spyClientSpan, spyAttemptSpan);
inOrder.verify(spyAttemptSpan).putAttribute("previous-rpc-attempts", AttributeValue.longAttributeValue(0));
inOrder.verify(spyAttemptSpan).putAttribute("transparent-retry", AttributeValue.booleanAttributeValue(false));
inOrder.verify(spyAttemptSpan, times(3)).addMessageEvent(messageEventCaptor.capture());
List<MessageEvent> events = messageEventCaptor.getAllValues();
assertEquals(MessageEvent.builder(MessageEvent.Type.SENT, 0).setCompressedMessageSize(882).build(), events.get(0));
assertEquals(MessageEvent.builder(MessageEvent.Type.SENT, 1).setUncompressedMessageSize(27).build(), events.get(1));
assertEquals(MessageEvent.builder(MessageEvent.Type.RECEIVED, 0).setCompressedMessageSize(255).setUncompressedMessageSize(90).build(), events.get(2));
inOrder.verify(spyAttemptSpan).end(EndSpanOptions.builder().setStatus(io.opencensus.trace.Status.OK).setSampleToLocalSpanStore(false).build());
inOrder.verify(spyClientSpan).end(EndSpanOptions.builder().setStatus(io.opencensus.trace.Status.OK).setSampleToLocalSpanStore(false).build());
inOrder.verifyNoMoreInteractions();
verifyNoMoreInteractions(tracer);
}
use of io.grpc.ClientStreamTracer in project grpc-java by grpc.
the class CensusModulesTest method subtestStatsHeadersPropagateTags.
private void subtestStatsHeadersPropagateTags(boolean propagate, boolean recordStats) {
// EXTRA_TAG is propagated by the FakeStatsContextFactory. Note that not all tags are
// propagated. The StatsContextFactory decides which tags are to propagated. gRPC facilitates
// the propagation by putting them in the headers.
TagContext clientCtx = tagger.emptyBuilder().putLocal(StatsTestUtils.EXTRA_TAG, TagValue.create("extra-tag-value-897")).build();
CensusStatsModule census = new CensusStatsModule(tagger, tagCtxSerializer, statsRecorder, fakeClock.getStopwatchSupplier(), propagate, recordStats, recordStats, recordStats, recordStats);
Metadata headers = new Metadata();
CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory = new CensusStatsModule.CallAttemptsTracerFactory(census, clientCtx, method.getFullMethodName());
// This propagates clientCtx to headers if propagates==true
ClientStreamTracer streamTracer = callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, headers);
streamTracer.streamCreated(Attributes.EMPTY, headers);
if (recordStats) {
// Client upstart record
StatsTestUtils.MetricsRecord clientRecord = statsRecorder.pollRecord();
assertNotNull(clientRecord);
assertNoServerContent(clientRecord);
assertEquals(2, clientRecord.tags.size());
TagValue clientMethodTag = clientRecord.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), clientMethodTag.asString());
TagValue clientPropagatedTag = clientRecord.tags.get(StatsTestUtils.EXTRA_TAG);
assertEquals("extra-tag-value-897", clientPropagatedTag.asString());
}
if (propagate) {
assertTrue(headers.containsKey(census.statsHeader));
} else {
assertFalse(headers.containsKey(census.statsHeader));
return;
}
ServerStreamTracer serverTracer = census.getServerTracerFactory().newServerStreamTracer(method.getFullMethodName(), headers);
// Server tracer deserializes clientCtx from the headers, so that it records stats with the
// propagated tags.
Context serverContext = serverTracer.filterContext(Context.ROOT);
// It also put clientCtx in the Context seen by the call handler
assertEquals(tagger.toBuilder(clientCtx).putLocal(RpcMeasureConstants.GRPC_SERVER_METHOD, TagValue.create(method.getFullMethodName())).build(), io.opencensus.tags.unsafe.ContextUtils.getValue(serverContext));
// Verifies that the server tracer records the status with the propagated tag
serverTracer.streamClosed(Status.OK);
if (recordStats) {
// Server upstart record
StatsTestUtils.MetricsRecord serverRecord = statsRecorder.pollRecord();
assertNotNull(serverRecord);
assertNoClientContent(serverRecord);
assertEquals(2, serverRecord.tags.size());
TagValue serverMethodTag = serverRecord.tags.get(RpcMeasureConstants.GRPC_SERVER_METHOD);
assertEquals(method.getFullMethodName(), serverMethodTag.asString());
TagValue serverPropagatedTag = serverRecord.tags.get(StatsTestUtils.EXTRA_TAG);
assertEquals("extra-tag-value-897", serverPropagatedTag.asString());
// Server completion record
serverRecord = statsRecorder.pollRecord();
assertNotNull(serverRecord);
assertNoClientContent(serverRecord);
serverMethodTag = serverRecord.tags.get(RpcMeasureConstants.GRPC_SERVER_METHOD);
assertEquals(method.getFullMethodName(), serverMethodTag.asString());
TagValue serverStatusTag = serverRecord.tags.get(RpcMeasureConstants.GRPC_SERVER_STATUS);
assertEquals(Status.Code.OK.toString(), serverStatusTag.asString());
assertNull(serverRecord.getMetric(DeprecatedCensusConstants.RPC_SERVER_ERROR_COUNT));
serverPropagatedTag = serverRecord.tags.get(StatsTestUtils.EXTRA_TAG);
assertEquals("extra-tag-value-897", serverPropagatedTag.asString());
}
// Verifies that the client tracer factory uses clientCtx, which includes the custom tags, to
// record stats.
streamTracer.streamClosed(Status.OK);
callAttemptsTracerFactory.callEnded(Status.OK);
if (recordStats) {
// Client completion record
StatsTestUtils.MetricsRecord clientRecord = statsRecorder.pollRecord();
assertNotNull(clientRecord);
assertNoServerContent(clientRecord);
TagValue clientMethodTag = clientRecord.tags.get(RpcMeasureConstants.GRPC_CLIENT_METHOD);
assertEquals(method.getFullMethodName(), clientMethodTag.asString());
TagValue clientStatusTag = clientRecord.tags.get(RpcMeasureConstants.GRPC_CLIENT_STATUS);
assertEquals(Status.Code.OK.toString(), clientStatusTag.asString());
assertNull(clientRecord.getMetric(DeprecatedCensusConstants.RPC_CLIENT_ERROR_COUNT));
TagValue clientPropagatedTag = clientRecord.tags.get(StatsTestUtils.EXTRA_TAG);
assertEquals("extra-tag-value-897", clientPropagatedTag.asString());
assertZeroRetryRecorded();
}
if (!recordStats) {
assertNull(statsRecorder.pollRecord());
}
}
use of io.grpc.ClientStreamTracer in project grpc-java by grpc.
the class ClientCallImpl method startInternal.
private void startInternal(Listener<RespT> observer, Metadata headers) {
checkState(stream == null, "Already started");
checkState(!cancelCalled, "call was cancelled");
checkNotNull(observer, "observer");
checkNotNull(headers, "headers");
if (context.isCancelled()) {
// Context is already cancelled so no need to create a real stream, just notify the observer
// of cancellation via callback on the executor
stream = NoopClientStream.INSTANCE;
final Listener<RespT> finalObserver = observer;
class ClosedByContext extends ContextRunnable {
ClosedByContext() {
super(context);
}
@Override
public void runInContext() {
closeObserver(finalObserver, statusFromCancelled(context), new Metadata());
}
}
callExecutor.execute(new ClosedByContext());
return;
}
applyMethodConfig();
final String compressorName = callOptions.getCompressor();
Compressor compressor;
if (compressorName != null) {
compressor = compressorRegistry.lookupCompressor(compressorName);
if (compressor == null) {
stream = NoopClientStream.INSTANCE;
final Listener<RespT> finalObserver = observer;
class ClosedByNotFoundCompressor extends ContextRunnable {
ClosedByNotFoundCompressor() {
super(context);
}
@Override
public void runInContext() {
closeObserver(finalObserver, Status.INTERNAL.withDescription(String.format("Unable to find compressor by name %s", compressorName)), new Metadata());
}
}
callExecutor.execute(new ClosedByNotFoundCompressor());
return;
}
} else {
compressor = Codec.Identity.NONE;
}
prepareHeaders(headers, decompressorRegistry, compressor, fullStreamDecompression);
Deadline effectiveDeadline = effectiveDeadline();
boolean deadlineExceeded = effectiveDeadline != null && effectiveDeadline.isExpired();
if (!deadlineExceeded) {
logIfContextNarrowedTimeout(effectiveDeadline, context.getDeadline(), callOptions.getDeadline());
stream = clientStreamProvider.newStream(method, callOptions, headers, context);
} else {
ClientStreamTracer[] tracers = GrpcUtil.getClientStreamTracers(callOptions, headers, 0, false);
stream = new FailingClientStream(DEADLINE_EXCEEDED.withDescription("ClientCall started after deadline exceeded: " + effectiveDeadline), tracers);
}
if (callExecutorIsDirect) {
stream.optimizeForDirectExecutor();
}
if (callOptions.getAuthority() != null) {
stream.setAuthority(callOptions.getAuthority());
}
if (callOptions.getMaxInboundMessageSize() != null) {
stream.setMaxInboundMessageSize(callOptions.getMaxInboundMessageSize());
}
if (callOptions.getMaxOutboundMessageSize() != null) {
stream.setMaxOutboundMessageSize(callOptions.getMaxOutboundMessageSize());
}
if (effectiveDeadline != null) {
stream.setDeadline(effectiveDeadline);
}
stream.setCompressor(compressor);
if (fullStreamDecompression) {
stream.setFullStreamDecompression(fullStreamDecompression);
}
stream.setDecompressorRegistry(decompressorRegistry);
channelCallsTracer.reportCallStarted();
stream.start(new ClientStreamListenerImpl(observer));
// Delay any sources of cancellation after start(), because most of the transports are broken if
// they receive cancel before start. Issue #1343 has more details
// Propagate later Context cancellation to the remote side.
context.addListener(cancellationListener, directExecutor());
if (effectiveDeadline != null && // If the context has the effective deadline, we don't need to schedule an extra task.
!effectiveDeadline.equals(context.getDeadline()) && // If the channel has been terminated, we don't need to schedule an extra task.
deadlineCancellationExecutor != null) {
deadlineCancellationFuture = startDeadlineTimer(effectiveDeadline);
}
if (cancelListenersShouldBeRemoved) {
// Race detected! ClientStreamListener.closed may have been called before
// deadlineCancellationFuture was set / context listener added, thereby preventing the future
// and listener from being cancelled. Go ahead and cancel again, just to be sure it
// was cancelled.
removeContextListenerAndCancelDeadlineFuture();
}
}
Aggregations