Skip to content

Move jsRpcSession span ownership into JsRpcSessionCustomEvent#6703

Closed
Ankcorn wants to merge 2 commits intocloudflare:mainfrom
Ankcorn:tankcorn/jsrpc-span-parenting
Closed

Move jsRpcSession span ownership into JsRpcSessionCustomEvent#6703
Ankcorn wants to merge 2 commits intocloudflare:mainfrom
Ankcorn:tankcorn/jsrpc-span-parenting

Conversation

@Ankcorn
Copy link
Copy Markdown
Member

@Ankcorn Ankcorn commented Apr 30, 2026

Today the span is buried in a TraceContext .attach()-ed to the WorkerInterface — the event can't reach it. This blocks runtime span enrichment from callImpl's response continuation (e.g. AI Gateway binding tags, #6695).

  1. Adds Fetcher::getJsRpcClient() returning {worker, sessionSpan}, and stores the SpanBuilder on JsRpcSessionCustomEvent for the session lifetime.
  2. Span ID is allocated before startRequest() so it works as userSpanParent for USER_SPAN_CONTEXT_PROPAGATION.
  3. OutgoingFactory variants keep their existing outer span — no jsRpcSession stacked on top.

Unblocks #6695

With the span reachable from the event, callImpl can apply enrichment directly via event->applyEnrichment(...).

This lets #6695 delete:

  • currentEnrichmentTc_ raw pointer field on Fetcher (with its "safe because JS is single-threaded" comment)
  • getEnrichmentTraceContext() virtual side-channel + every override
  • The KJ_IF_SOME(tc, clientWithTracing.traceContext) branch + manual kj::heap<TraceContext> lifetime juggling

What stays in #6695: callee-side setJsrpcSessionAttributes API — i.e. the actual feature.

@Ankcorn Ankcorn requested review from a team as code owners April 30, 2026 15:01
@Ankcorn Ankcorn changed the title Tankcorn/jsrpc span parenting Move jsRpcSession span ownership into JsRpcSessionCustomEvent Apr 30, 2026
Ankcorn added 2 commits April 30, 2026 15:06
Adds Case 7 to tracing-hierarchy-instrumentation-test: an RPC call made
inside enterSpan() must produce a jsRpcSession user span whose parent is
the enterSpan, not the top-level onset span. This is the RPC analog of
the existing fetchInsideEnterSpan case.
The jsRpcSession user span is now created in Fetcher::getJsRpcClient() —
a new helper that returns the WorkerInterface plus the span — and
transferred to the JsRpcSessionCustomEvent where it lives as a member
SpanBuilder until the event is destroyed (i.e. session end).

Previously the span was created inside getClientWithTracing() and
attached to the WorkerInterface via .attach(). The event itself had no
visibility into the span, which made it impossible for callImpl() to
reach it for runtime enrichment (e.g. AI Gateway binding span tags).

Behavioural notes:
- Span created on the caller side before startRequest() so its ID is
  available for USER_SPAN_CONTEXT_PROPAGATION (the callee's onset event
  reports this span as its parent).
- Direct channel variants (uint, IoOwn<SubrequestChannel>) get a
  jsRpcSession span. OutgoingFactory variants (DurableObject stubs,
  cross-process actors) already create their own outer span
  (e.g. durable_object_subrequest), so jsRpcSession is omitted to avoid
  redundancy. This matches pre-existing behaviour for those variants.
- ioContext.now() (I/O time) is used for the explicit start time so we
  remain Spectre-safe and deterministic in test mode.
@Ankcorn Ankcorn force-pushed the tankcorn/jsrpc-span-parenting branch from 1ca14e7 to 04e17f6 Compare April 30, 2026 15:09
@Ankcorn Ankcorn closed this Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant