Skip to content

Fix context propagation when the same Runnable is submitted to a ThreadPoolExecutor multiple times - #12379

Closed
amarziali wants to merge 1 commit into
masterfrom
andrea.marziali/runnable-submission
Closed

Fix context propagation when the same Runnable is submitted to a ThreadPoolExecutor multiple times#12379
amarziali wants to merge 1 commit into
masterfrom
andrea.marziali/runnable-submission

Conversation

@amarziali

Copy link
Copy Markdown
Contributor

What Does This Do

Fix context propagation when the same Runnable instance is submitted concurrently, while preserving the original runnable identity. Each submission now owns its continuation independently, preventing missing or incorrectly parented traces.

The change preserves ThreadPoolExecutor subclass compatibility, handles rejection/removal/shutdown cleanup, and inspects queue compatibility only when a collision occurs.

Benchmark

JMH on JDK 25/macOS found:

  • Approximately +24 B per active propagated submission for the correctness ownership token.
  • No additional allocation for root-context or non-delegating subclass submissions.
  • No statistically significant latency regression across base, delegating, and non-delegating executors.

Motivation

Additional Notes

Contributor Checklist

Jira ticket: [PROJ-IDENT]

@amarziali

Copy link
Copy Markdown
Contributor Author

@DataDog review

@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
Patch Coverage: 29.66%
Overall Coverage: 62.70% (+3.68%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 537bbdd | Docs | View more details | Give us feedback!

@datadog-prod-us1-5 datadog-prod-us1-5 Bot 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.

Datadog Autotest: FAIL

The ownership logic can cancel the wrong context and can miss cleanup when queue admission throws. Manual removal can block executor termination, and rejection can inflate cancellation metrics.

Open Bits AI session

🤖 Datadog Autotest · Commit 537bbdd · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

}
owner = queued;
State state = contextStore.get(queued);
continuation = state == null ? null : state.getCancellableContinuation();

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.

P2 Cancel only the removed submission context

The remaining traced submission runs without its parent context.

Assertion details
  • Input: Queue one reusable task with root context. Queue the same task with traced context. Then remove one task.
  • Expected: Removal releases only the continuation that belongs to the removed queue entry.
  • Actual: The scan reads the later traced continuation from task-wide state. It then releases that continuation after it removes the earlier root-context entry.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest · Open Bits AI session

if (queued instanceof Wrapper) {
if (tpe.getQueue().remove(queued)) {
((Wrapper<?>) queued).cancel();
return true;

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.

P2 Run the termination check after manual removal

The executor can stay in shutdown state, and awaitTermination can wait forever.

Assertion details
  • Input: Shut down an executor that has no workers and one wrapped task. Then remove that task by its original identity.
  • Expected: The executor checks for termination after it removes the final queued task.
  • Actual: The advice removes the wrapper and skips the executor method body. It does not call the executor termination check.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest · Open Bits AI session

InstrumentationContext.get(Runnable.class, State.class),
task,
currentContext(),
tpe);

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.

P2 Release context when queue admission throws

The continuation can keep a trace open and can later give reused work the wrong parent context.

Assertion details
  • Input: Submit a traced task to a queue whose offer operation throws, such as an incompatible task in a populated PriorityBlockingQueue.
  • Expected: The executor releases the owned continuation when queue admission throws.
  • Actual: The enter advice installs a tagged continuation. Generic exception cleanup ignores this continuation, and this advice has no exception cleanup.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest · Open Bits AI session

if (wrapper != null) {
wrapper.cancel();
} else if (continuation != null) {
continuation.release();

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.

P2 Do not release a resumed rejection twice

Executor saturation inflates continuation cancellation health metrics.

Assertion details
  • Input: Reject any propagated task through an instrumented rejection handler.
  • Expected: Rejection ends each continuation once and records one finished continuation.
  • Actual: Scope close finishes the resumed continuation. The following explicit release records a second cancellation.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest · Open Bits AI session

@dd-octo-sts

dd-octo-sts Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🟡 Java Benchmark SLOs — Performance SLO warning (near threshold)

Suite Status
Startup 🟡 warning

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 13.85 s 13.97 s [-1.7%; -0.1%] (maybe better)
startup:insecure-bank:tracing:Agent 12.87 s 12.99 s [-1.7%; -0.2%] (maybe better)
startup:petclinic:appsec:Agent 16.91 s 16.79 s [-0.2%; +1.6%] (no difference)
startup:petclinic:iast:Agent 16.86 s 16.98 s [-1.6%; +0.1%] (no difference)
startup:petclinic:profiling:Agent 16.77 s 16.23 s [-1.2%; +8.0%] (no difference)
startup:petclinic:sca:Agent 16.84 s 16.72 s [-0.1%; +1.6%] (no difference)
startup:petclinic:tracing:Agent 16.10 s 16.12 s [-1.0%; +0.8%] (no difference)

Commit: 537bbdd3 · 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.

@amarziali amarziali closed this Sep 2, 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