in tchannel-core/src/main/java/com/uber/tchannel/handlers/RequestRouter.java [241:288]
private ListenableFuture<? extends Response> sendRequestToAsyncHandler(
final AsyncRequestHandler asyncHandler, final Request request
) {
// span used to trace this request
// Tracer and TracingContext are only present when the channel is created with them
// therefore can be null.
final Span span = topChannel.getTracer() == null
? null
: Tracing.startInboundSpan(request, topChannel.getTracer(), topChannel.getTracingContext());
ListenableFuture<? extends Response> responseFuture = asyncHandler.handleAsync(request);
// Add callback handlers that close out the tracing span and then proxy the response.
Futures.addCallback(responseFuture, new FutureCallback<Response>() {
@Override
public void onSuccess(Response response) {
if (response != null
&& response.getResponseCode() == ResponseCode.Error
&& span != null) {
span.setTag(Tags.ERROR, true);
}
closeRequestAndSpan();
}
@Override
public void onFailure(@NotNull Throwable e) {
if (span != null) {
span.setTag(Tags.ERROR, true);
span.log(ImmutableMap.of(Fields.ERROR_OBJECT, e));
}
closeRequestAndSpan();
}
private void closeRequestAndSpan() {
request.releaseQuietly();
if (span != null) {
span.finish();
}
}
}, listeningExecutorService); // execute the callback asynchronously, not on the thread that resolves the future
if (span != null) { // if we pushed something on tracing context stack in Tracing.startInboundSpan(...)
topChannel.getTracingContext().popSpan(); // then pop it
}
return responseFuture;
}