Source:
<code>public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { if (isInit == false) return invoker.invoke(invocation); RpcContext rpcContext = RpcContext.getContext(); Kind kind = rpcContext.isProviderSide() ? Kind.SERVER : Kind.CLIENT; final Span span; if (kind.equals(Kind.CLIENT)) { span = tracer.nextSpan(); injector.inject(span.context(), invocation.getAttachments()); } else { TraceContextOrSamplingFlags extracted = extractor.extract(invocation.getAttachments()); span = extracted.context() != null ? tracer.joinSpan(extracted.context()) : tracer.nextSpan(extracted); } if (!span.isNoop()) { span.kind(kind); String service = invoker.getInterface().getSimpleName(); String method = RpcUtils.getMethodName(invocation); span.name(service + "/" + method); parseRemoteAddress(rpcContext, span); span.start(); } boolean isOneway = false, deferFinish = false; try (Tracer.SpanInScope scope = tracer.withSpanInScope(span)) { Result result = invoker.invoke(invocation); if (result.hasException()) { onError(result.getException(), span); } isOneway = RpcUtils.isOneway(invoker.getUrl(), invocation); Future<Object> future = rpcContext.getFuture(); <START> if (future instanceof FutureAdapter) { <END> deferFinish = true; ResponseFuture responseFuture = ((FutureAdapter<Object>) future).getFuture(); ResponseFuture responseFutureDelegate = new AsyncResponseFutureDelegate(span, responseFuture); RpcContext.getContext().setFuture(new FutureAdapter<>(responseFutureDelegate)); } return result; } catch (Error | RuntimeException e) { onError(e, span); throw e; } finally { if (isOneway) { span.flush(); } else if (!deferFinish) { span.finish(); } } }</code><technical_language>concerned this change. Before, set a callback. This ensures span is finished in case user sets a callback. Now, don't. I this is dangerous lead leaked spans. I push a commit branch for review</technical_language>

Target:
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { if (isInit == false) return invoker.invoke(invocation); RpcContext rpcContext = RpcContext.getContext(); Kind kind = rpcContext.isProviderSide() ? Kind.SERVER : Kind.CLIENT; final Span span; if (kind.equals(Kind.CLIENT)) { span = tracer.nextSpan(); injector.inject(span.context(), invocation.getAttachments()); } else { TraceContextOrSamplingFlags extracted = extractor.extract(invocation.getAttachments()); span = extracted.context() != null ? tracer.joinSpan(extracted.context()) : tracer.nextSpan(extracted); } if (!span.isNoop()) { span.kind(kind); String service = invoker.getInterface().getSimpleName(); String method = RpcUtils.getMethodName(invocation); span.name(service + "/" + method); parseRemoteAddress(rpcContext, span); span.start(); } boolean isOneway = false, deferFinish = false; try (CurrentTraceContext.Scope scope = current.newScope(span.context())) { Result result = invoker.invoke(invocation); isOneway = RpcUtils.isOneway(invoker.getUrl(), invocation); if (!span.isNoop()) { deferFinish = ensureSpanFinishes(rpcContext, span, result); } return result; } catch (Error | RuntimeException e) { onError(e, span); throw e; } finally { if (isOneway) { span.flush(); } else if (!deferFinish) { span.finish(); } } }