Skip to content

Improve structured concurrency instrumentation#11759

Open
PerfectSlayer wants to merge 5 commits into
masterfrom
bbujon/virtual-threads
Open

Improve structured concurrency instrumentation#11759
PerfectSlayer wants to merge 5 commits into
masterfrom
bbujon/virtual-threads

Conversation

@PerfectSlayer

Copy link
Copy Markdown
Contributor

What Does This Do

This PRs improves the structured concurrency instrumentation, in charge of context tracking for the JEP  505 (JDK 25), JEP 525 (JDK 26) and JEP 533 (JDK 27). In particular it:

  • Fixes potential continuation leak when the joined cancels the scope before the task could be run,
  • Introduces instrumentation tests (previously blocked due to Groovy / Spock not being able to run on JDK 25+ but recent JUnit testing capabilities allowed to build such instrumentation tests)
  • Introduces dedicated instrumentation module now there are two instrumentations - only for JDK 25+, not needed for JDK 21

Motivation

Prevent continuation (hence traces) leaks and improves reliability with dedicated unit tests.

Additional Notes

Structucred Concurrency is still a JDK feature in preview.

Contributor Checklist

  • Format the title according to the contribution guidelines
  • Assign the type: and (comp: or inst:) labels in addition to any other useful labels
  • Avoid using close, fix, or any linking keywords when referencing an issue
    Use solves instead, and assign the PR milestone to the issue
  • Update the CODEOWNERS file on source file addition, migration, or deletion
  • Update public documentation with any new configuration flags or behaviors
  • Add your completed PR to the merge queue by commenting /merge. You can also:
    • Customize the commit message associated with the merge with /merge --commit-message "..."
    • Remove your PR from the merge queue with /merge -c
    • Skip all merge queue checks with /merge -f --reason "reason"; please use this judiciously, as some checks do not run at the PR-level (note: the PR still needs to be mergeable, this will only skip the pre-merge build)
    • Get more information in this doc

Jira ticket: [PROJ-IDENT]

@PerfectSlayer PerfectSlayer added type: enhancement Enhancements and improvements inst: java Core Java language instrumentation labels Jun 28, 2026
@PerfectSlayer PerfectSlayer requested review from a team as code owners June 28, 2026 12:38
@PerfectSlayer PerfectSlayer requested review from amarziali and removed request for a team June 28, 2026 12:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 405ab8c46d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +54 to +56
if (subtask instanceof Runnable && StructuredTaskScopeHelper.isCancelled(scope)) {
ContextStore<Runnable, State> contextStore = get(Runnable.class, State.class);
cancelTask(contextStore, (Runnable) subtask);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not cancel started subtasks' continuations

When a scope is canceled by another subtask or by a timeout after StructuredTaskScopeImpl.fork has already started this subtask but before this exit advice runs, this check treats the returned subtask as if it was never started and cancels its captured continuation. If the subtask thread has not entered run() yet, the Runnable advice will then find no continuation, so started subtasks under cancel-on-completion joiners such as anySuccessfulResultOrThrow() (or failure-canceling joiners) can run without the parent trace context. This cleanup should be limited to subtasks that were actually skipped, not every subtask returned while the scope is canceled at method exit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an issue, I will handle it next week.

@dd-octo-sts

dd-octo-sts Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.85 s 14.82 s [-0.9%; +1.3%] (no difference)
startup:insecure-bank:tracing:Agent 13.65 s 13.66 s [-0.9%; +0.7%] (no difference)
startup:petclinic:appsec:Agent 16.84 s 16.11 s [+0.3%; +8.8%] (maybe worse)
startup:petclinic:iast:Agent 16.93 s 17.05 s [-1.4%; -0.0%] (maybe better)
startup:petclinic:profiling:Agent 16.93 s 16.95 s [-1.1%; +0.8%] (no difference)
startup:petclinic:sca:Agent 16.97 s 16.56 s [+1.5%; +3.4%] (significantly worse)
startup:petclinic:tracing:Agent 16.11 s 15.70 s [-1.8%; +7.0%] (no difference)

Commit: 829131e1 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@PerfectSlayer PerfectSlayer force-pushed the bbujon/virtual-threads branch from 405ab8c to 2c1064f Compare June 28, 2026 12:59

@amarziali amarziali left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks fine to me. Left one suggestion. Also agree with the issue raised by codex

ClassLoader classLoader = StructuredTaskScopeHelper.class.getClassLoader();
Class<?> scopeClass =
Class.forName("java.util.concurrent.StructuredTaskScope", false, classLoader);
return publicLookup().findVirtual(scopeClass, "isCancelled", methodType(boolean.class));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use also our datadog.trace.util.MethodHandles class that already handle class loading, method finding and exception suppression

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! I will have a look if I still need it 👍

@PerfectSlayer

Copy link
Copy Markdown
Contributor Author

Also agree with the issue raised by codex

Yeah, I did the testing migration and fixes by hand but I let Claude handles the joiner case.
Like every try with core instrumentation, I got it wrong and it costs me more time to fix it afterwards 😮‍💨

@PerfectSlayer PerfectSlayer force-pushed the bbujon/virtual-threads branch from 6cdff97 to 829131e Compare June 29, 2026 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

inst: java Core Java language instrumentation type: enhancement Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants