[
https://issues.apache.org/jira/browse/CAMEL-23225?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18068276#comment-18068276
]
Guillaume Nodet commented on CAMEL-23225:
-----------------------------------------
_Claude Code on behalf of Guillaume Nodet_
After thorough investigation, we recommend closing this issue as Not A Problem.
Here is the full analysis:
h3. Background
The issue reported that Spring Boot's {{ThreadPoolTaskExecutor}} (used in
{{camel-platform-http-starter}}) doesn't propagate OpenTelemetry context across
threads, causing context leaks.
Two PRs were attempted:
* [apache/camel#22190|https://github.com/apache/camel/pull/22190] — ported
{{Context.taskWrapping()}} thread pool wrappers from deprecated
camel-opentelemetry to camel-opentelemetry2. *Reverted* by
[apache/camel#22254|https://github.com/apache/camel/pull/22254].
*
[apache/camel-spring-boot#1730|https://github.com/apache/camel-spring-boot/pull/1730]
— added a Spring Boot {{TaskDecorator}} to propagate OTel context. *Closed*
after review feedback.
h3. Why no fix is needed
The {{camel-opentelemetry2}} module is *designed* not to depend on ThreadLocal
context propagation. Per the [design
doc|https://github.com/apache/camel/blob/main/proposals/tracing.adoc] and
confirmed by the component author (@squakez) in
[camel-spring-boot#1730|https://github.com/apache/camel-spring-boot/pull/1730#issuecomment-2781052771]:
* Trace context is propagated exclusively via *Exchange headers* (W3C
{{traceparent}}), not ThreadLocal.
* Span storage uses Exchange properties ({{SpanStorageManagerExchange}}), not
ThreadLocal.
* Thread pool wrapping ({{Context.taskWrapping()}}) contradicts this design.
h3. How context actually flows across thread boundaries
We verified that all async patterns work correctly without any ThreadLocal
propagation:
* *WireTap*: {{exchange.copy()}} deep-copies all headers including
{{traceparent}} to the new Exchange (verified by {{AsyncWiretapTest}} — 10
traces, correct hierarchy)
* *RecipientList*: reuses the same Exchange, headers preserved (verified by
{{AsyncTest}})
* *CXF REST async*: {{inject()}} writes {{traceparent}} to Exchange headers →
CXF copies to HTTP headers → REST endpoint creates new Exchange from HTTP
headers → {{extract()}} reads them back (verified by {{AsyncCXFTest}})
* *HTTP inbound*: Platform HTTP Vert.x / Netty HTTP copy ALL HTTP request
headers (including {{traceparent}}) into Exchange headers before Camel
processes them
The {{BAGGAGE_CAMEL_FLAG}} mechanism (added in
[CAMEL-22648|https://issues.apache.org/jira/browse/CAMEL-22648] / [PR
#20720|https://github.com/apache/camel/pull/20720]) handles a specific edge
case: when a third-party component (Vert.x, OTel Java agent) sets a span in
{{Context.current()}} before Camel processes a message via direct in-process
call (no HTTP boundary). This is intentional and working correctly — it does
not require thread pool wrapping.
h3. Recommendation
Close this issue as Not A Problem. No changes are needed in either camel-core
or camel-spring-boot. The existing design handles cross-thread context
propagation via Exchange headers, and the {{BAGGAGE_CAMEL_FLAG}} handles the
in-process integration edge case.
> Spring Boot's default ThreadPoolTaskExecutor doesn't propagate OpenTelemetry
> Context
> ------------------------------------------------------------------------------------
>
> Key: CAMEL-23225
> URL: https://issues.apache.org/jira/browse/CAMEL-23225
> Project: Camel
> Issue Type: Bug
> Components: camel-opentelemetry
> Reporter: John Poth
> Assignee: Guillaume Nodet
> Priority: Major
>
> When using camel-opentelemetry-starter (and v2), let's propagate the
> OpenTelemetry context in Spring Boot's default ThreadPoolTaskExecutor (used
> in camel-platform-http-starter). This causes context leaks
--
This message was sent by Atlassian Jira
(v8.20.10#820010)