open-telemetry / open-telemetry/opentelemetry-java-instrumentation
SOFA RPC client span remains open when a custom async transport bypasses FilterChain.onAsyncResponse
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 2.6k
- Forks
- 1.2k
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 228
Description
Describe the bug
The SOFA RPC instrumentation starts a client span for an asynchronous consumer invocation and stores its tracing state on the original SofaRequest. The span is completed later from Filter.onAsyncResponse(...).
A custom asynchronous transport callback can receive the response or exception and invoke the application callback directly without notifying the consumer FilterChain. In that case, the client span remains open and is not exported.
The application-facing API may still behave synchronously; “asynchronous” here only refers to the transport response lifecycle.
Steps to reproduce
- Run a SOFA RPC consumer with OpenTelemetry Java Agent 2.29.0 and the SOFA RPC instrumentation enabled.
- Use a custom asynchronous transport callback that retains the original
ConsumerConfigandSofaRequest. - In
onResponseoronException, invoke the application callback directly without callingFilterChain.onAsyncResponse(...). - Send one successful request and one failing request.
- Inspect exported spans.
A minimal callback shape is:
final class CustomInvokeCallback {
private final ConsumerConfig<?> consumerConfig;
private final SofaRequest request;
private final SofaResponseCallback callback;
void onResponse(Object rawResponse) {
SofaResponse response = convert(rawResponse);
callback.onAppResponse(response.getAppResponse(), request.getMethodName(), request);
}
void onException(Throwable error) {
callback.onAppException(error, request.getMethodName(), request);
}
}
Expected behavior
Successful and failed requests each produce exactly one completed SOFA RPC client span. The span retains the original parent, records the correct outcome, and covers the transport duration.
Actual behavior
The request-side tracing filter starts the span, but no asynchronous filter completion occurs. The client span therefore remains unfinished and is not exported.
Javaagent or library instrumentation version
OpenTelemetry Java Agent 2.29.0
Environment
- JDK: Java 8 application runtime
- OS: Linux
- SOFA RPC: 5.12.x-compatible runtime
Additional context
Would the maintainers accept a generic, strongly typed, idempotent completion entry point for custom asynchronous transports/extensions in the existing sofa-rpc-5.4 instrumentation?
The proposed behavior would:
- reuse the current SOFA RPC client instrumenter;
- complete only tracing state already created for the original request;
- be safe when state is absent or already completed;
- avoid running the full filter chain or any application filters;
- add no new span, propagator, exporter, or user configuration.
If this lifecycle must instead be fixed exclusively by the transport implementation, guidance on the preferred ownership boundary would be helpful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in the existing sofa-rpc-5.4 instrumentation, following the request-side tracing filter and Filter.onAsyncResponse(...) completion path. Inspect how tracing state is stored on SofaRequest and how ConsumerConfig and SofaResponseCallback are used by custom transports. Done means successful and failed direct callbacks each complete exactly one existing client span, preserving its parent and transport duration without running the filter chain.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100