otel-thread-ctx: add ThreadContext.invalidate() to flip valid byte - #383
Merged
Conversation
When an SDK finishes a span, calling clearContext() on the current async-context frame detaches the ThreadContext only from that frame. Sibling and detached-continuation frames that already inherited the reference keep holding the same JS object — and with it the same underlying native record — so an out-of-process reader sampling those threads still sees the finished span's trace / span IDs as active. invalidate() writes 0 to the record's `valid` header byte in place, using the same volatile+atomic_signal_fence protocol the constructor and Append() use for header bytes readers may race with. Because every async-context frame holding this ThreadContext reference observes the same shared record buffer, a single invalidate() drops the record out of scope for every such frame at once — readers see valid=0 and MUST ignore the record per OTEP-4947. The method is idempotent, safe under repeated calls, and orthogonal to attrs_data mutation: appendAttributes after invalidate is still observable in the record bytes, but readers honor the valid=0 flag regardless.
Overall package sizeSelf size: 2.46 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | pprof-format | 2.3.0 | 503.97 kB | 503.97 kB | | source-map | 0.8.0 | 185.66 kB | 185.66 kB | | node-gyp-build | 4.8.4 | 13.86 kB | 13.86 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
This comment has been minimized.
This comment has been minimized.
szegedi
marked this pull request as ready for review
August 6, 2026 14:31
szegedi
requested review from
IlyasShabi,
nsavoire and
r1viollet
as code owners
August 6, 2026 14:31
Open
2 tasks
IlyasShabi
approved these changes
Aug 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
ThreadContext.invalidate()to the OTEP-4947 writer's addon-exposed API. Writes0into the record'svalidheader byte in place, using the same volatile +atomic_signal_fenceprotocol the constructor andAppend()already use for header bytes an out-of-process reader can race with.Why
When an SDK finishes a span,
clearContext()on the current async-context frame detaches theThreadContextonly from that frame. Sibling and detached-continuation frames that already inherited the reference keep holding the same JS object — and with it the same underlying native record — so an eBPF reader sampling those contexts still sees the finished span's trace / span IDs as active. This is admittedly rare, but a corner case worth addressing.Every async-context frame holding the same
ThreadContextreference observes the same shared record buffer, so a singleinvalidate()drops the record out of scope for every such frame at once. Readers seevalid=0and MUST ignore the record per OTEP-4947.Addresses Codex review point #2 on DataDog/dd-trace-js#9210 ("Clear inherited contexts after finish"). The dd-trace-js follow-up wiring
onSpanFinished→cached.context.invalidate()will land in a separate PR after this addon change ships.Same change ported to upstream at polarsignals/custom-labels (branch `otel-thread-ctx-invalidate`).
Test plan
Jira: PROF-15665