Skip to content

feat(rxjava3): add RxJava 3 context propagation instrumentation#11505

Draft
wconti27 wants to merge 8 commits into
masterfrom
apm-ai-toolkit/new_integration/rxjava3/20260529-141514
Draft

feat(rxjava3): add RxJava 3 context propagation instrumentation#11505
wconti27 wants to merge 8 commits into
masterfrom
apm-ai-toolkit/new_integration/rxjava3/20260529-141514

Conversation

@wconti27
Copy link
Copy Markdown
Contributor

🤖 Generated with APM Instrumentation Toolkit

What Does This Do

Adds instrumentation for RxJava 3 (io.reactivex.rxjava3:rxjava) — context propagation across async reactive subscription boundaries for all 5 reactive types.

Motivation

Customer request for RxJava 3 support. RxJava 2 instrumentation already exists; this extends coverage to the v3 API which uses a new package namespace (io.reactivex.rxjava3.core).

Additional Notes

Design: Context propagation only — no new spans created. Mirrors the existing rxjava-2.0 module exactly:

  • Hooks each reactive type's constructor (capture active context) and subscribe() (wrap observer with tracing wrapper)
  • Observable, Flowable, Single, Completable, Maybe — all 5 types instrumented
  • Flowable handles two subscribe() overloads: subscribe(Subscriber) and subscribe(FlowableSubscriber) — the latter is new in RxJava 3 and shares a single Advice class via DYNAMIC typing + TracingSubscriber implementing both interfaces
  • RxJava3AsyncResultExtension — equivalent of RxJavaAsyncResultExtension in rxjava-2.0, extends spans until reactive chains complete for @WithSpan-annotated methods

Known limitation: Context propagation through Maybe.delay() (computation scheduler) does not produce child spans in the current implementation — the delayed Flowable tests provide equivalent delay coverage. Tracked as a follow-up investigation.

Contributor Checklist

Jira ticket: [PROJ-IDENT]

🤖 Generated with APM Instrumentation Toolkit

@wconti27 wconti27 added apm-integration-toolkit PR created by the APM Instrumentation Toolkit ai-generated AI generated code labels May 29, 2026
@datadog-prod-us1-4

This comment has been minimized.

wconti27 added 2 commits May 29, 2026 12:31
Remove toolkit-added skills (apm-integrations, datadog-semantics,
observability-patterns) and restore .claude to match master branch.
Remove the .claude/ .gitignore entry added by mistake.
@wconti27 wconti27 force-pushed the apm-ai-toolkit/new_integration/rxjava3/20260529-141514 branch from 97cd6bd to a3779c2 Compare May 29, 2026 16:35
@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented May 29, 2026

🟢 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 13.94 s 13.90 s [-0.8%; +1.3%] (no difference)
startup:insecure-bank:tracing:Agent 12.82 s 12.97 s [-2.5%; +0.1%] (no difference)
startup:petclinic:appsec:Agent 16.63 s 16.60 s [-1.1%; +1.5%] (no difference)
startup:petclinic:iast:Agent 16.66 s 16.62 s [-1.1%; +1.5%] (no difference)
startup:petclinic:profiling:Agent 16.58 s 16.57 s [-1.6%; +1.6%] (no difference)
startup:petclinic:tracing:Agent 15.80 s 15.79 s [-1.6%; +1.8%] (no difference)

Commit: 66ab94b7 · 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.

Copy link
Copy Markdown
Contributor

@amarziali amarziali left a comment

Choose a reason for hiding this comment

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

The delayedMaybe testing raises an issue highlighting that continuations are getting leaked on the scheduler - it should be excluded from propagation to have a safe instrumentation

@AutoService(InstrumenterModule.class)
public final class RxJavaModule extends InstrumenterModule.ContextTracking {
public RxJavaModule() {
super("rxjava");
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.

add also rxjava-3

Comment on lines +33 to +38
transformer.applyAdvice(
isMethod()
.and(named("subscribe"))
.and(takesArguments(1))
.and(takesArgument(0, named("org.reactivestreams.Subscriber"))),
getClass().getName() + "$PropagateParentSpanAdvice");
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.

prise to have spotted both method. However it looks like that this version delegate to the method above that's public final. So that this can be avoided to be instrumented since it only delegates to the latter

* to argument slots of either {@code Flowable#subscribe(Subscriber)} or {@code
* Flowable#subscribe(FlowableSubscriber)} from the same Advice class.
*/
public final class TracingSubscriber<T> implements FlowableSubscriber<T>, Subscriber<T> {
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.

it will only need to implement FlowableSubscriber if we do not instrument anymore the subscribe(Subscriber) version on the FlowableInstrumentation

Comment on lines +49 to +52
// Delayed operators (Maybe.delay) run on a scheduler thread; spans may outlive the
// subscribing scope, causing the pending-trace reference count to go negative when
// strictTraceWrites is on. Mirror RxJava2Test's useStrictTraceWrites() = false.
testConfig.strictTraceWrites(false);
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.

This is deliberately cheating on tests. There is indeed an threadpool where we leak continuations and should be excluded from propagating scopes

testImplementation project(':dd-java-agent:instrumentation:datadog:tracing:trace-annotation')
testImplementation project(':dd-java-agent:instrumentation:opentelemetry:opentelemetry-annotations-1.20')

testImplementation group: 'io.reactivex.rxjava3', name: 'rxjava', version: '3.1.10'
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.

the minimum version to test is 3.0.0 and not 3.1.10 unless limitations that should be explicitly commented

testImplementation project(':dd-java-agent:instrumentation:opentelemetry:opentelemetry-annotations-1.20')

testImplementation group: 'io.reactivex.rxjava3', name: 'rxjava', version: '3.1.10'
testImplementation group: 'io.opentelemetry.instrumentation', name: 'opentelemetry-instrumentation-annotations', version: '1.28.0'
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.

I would also add previous versions of this instrumentation in order to check for overlaps when testing

group = "io.reactivex.rxjava3"
module = "rxjava"
versions = "[3.0.0,)"
assertInverse = 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.

this is not enough. previous versions of rxjava has io.reactivex.rxjava2 group hence a specific fail section is needed here

Comment on lines +549 to +556
/**
* Tracks a known bug: same as {@link #delayedMaybe()} but with two delay/map stages, so the
* downstream chain must survive multiple computation-scheduler hops. Re-enable once Maybe
* scheduler-hop instrumentation is fixed.
*/
@Disabled(
"Known issue: Maybe.delay() loses span context through the computation scheduler — "
+ "delayed Flowable provides equivalent coverage in the meantime")
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.

This is good to have tracked down the issue in a test. Also, the IA had an idea from where the issue came. This should be addressed by excluding the propagation on the scheduler otherwise we leak continuations and the spans won't close correctly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-generated AI generated code apm-integration-toolkit PR created by the APM Instrumentation Toolkit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants