Skip to content

Keep the current sampler when the Jaeger sampling strategy is unchanged - #8946

Open
liotur wants to merge 2 commits into
open-telemetry:mainfrom
liotur:jaeger-remote-sampler-keep-unchanged-strategy
Open

liotur wants to merge 2 commits into
open-telemetry:mainfrom
liotur:jaeger-remote-sampler-keep-unchanged-strategy

Conversation

@liotur

@liotur liotur commented Oct 13, 2026 •

Copy link
Copy Markdown

Part of #2465

JaegerRemoteSampler builds a new sampler from every poll response, even when the strategy has not changed. For a RATE_LIMITING strategy that means a new RateLimiter that starts with a full balance, so under load each poll (every 60 seconds by default) lets through up to maxTracesPerSecond extra traces.

This change remembers the last applied response and keeps the current sampler when the response bytes are the same. If the bytes differ for any reason, the sampler is rebuilt as it is today. The bytes are saved only after the new sampler is built, so a response that fails to parse does not cause the next unchanged response to rebuild the sampler. The sender handles responses asynchronously and the next poll does not wait for the previous response, so two responses can be handled at the same time; a dedicated lock keeps the sampler and the saved bytes in step. Comparing raw bytes keeps the change small; I can compare the decoded SamplingStrategyResponse instead if you prefer.

This covers the first part of the issue. Keeping the limiter's state when only the rate changes (the Update() approach from jaeger-client-go mentioned in the issue) needs a RateLimiter that can change its rate in place, and that class lives in sdk-common's internal package, so I'd rather do it in a separate PR and leave the issue open. For comparison, jaeger-client-java also replaced its rate limiting sampler with a new one whenever the rate changed.

Added JaegerRemoteSamplerTest#unchangedStrategy_keepsSampler, which fails without the fix and passes with it. ./gradlew :sdk-extensions:jaeger-remote-sampler:check passes.

@liotur
liotur requested a review from a team as a code owner October 13, 2026 07:14
@linux-foundation-easycla

linux-foundation-easycla Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: liotur / name: Armen Petrosyan (ede2837)

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-11-09 19:24 UTC

Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):

  • Inline threads: 1
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

JaegerRemoteSampler built a new sampler from every poll response, even
when the strategy had not changed. For a RATE_LIMITING strategy that
means a new RateLimiter with a full balance on every poll, so under load
each poll lets through up to maxTracesPerSecond extra traces.

Remember the last applied response and keep the current sampler when the
response bytes are the same. Keeping the limiter state when only the
rate changes is left for a follow-up.

Part of open-telemetry#2465
@liotur
liotur force-pushed the jaeger-remote-sampler-keep-unchanged-strategy branch from df22bfd to ede2837 Compare October 13, 2026 07:17
@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 36.00000% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.28%. Comparing base (387f5c5) to head (7e856bb).
⚠️ Report is 46 commits behind head on main.

Files with missing lines Patch % Lines
...trace/jaeger/sampler/SamplingStrategyResponse.java 25.58% 21 Missing and 11 partials ⚠️

❌ Your patch check has failed because the patch coverage (36.00%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8946      +/-   ##
============================================
- Coverage     90.65%   90.28%   -0.38%     
- Complexity    10887    11022     +135     
============================================
  Files          1015     1021       +6     
  Lines         29731    30177     +446     
  Branches       3876     3950      +74     
============================================
+ Hits          26953    27245     +292     
- Misses         1860     1962     +102     
- Partials        918      970      +52     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.


@GuardedBy("lock")
@Nullable
private byte[] lastResponseMessage;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approach makes sense, but let's store the parsed SamplingStrategyResponse and do an equality check against that instead of the raw bytes.

The unchanged check held the last response message and compared bytes, so
a semantically identical strategy that happened to be encoded differently
would still have replaced the sampler.

Give SamplingStrategyResponse and its nested strategies equals/hashCode
and keep the last parsed response instead.
@liotur

liotur commented Nov 6, 2026

Copy link
Copy Markdown
Author

Done — it now keeps the last parsed SamplingStrategyResponse and compares that.

That needed equals/hashCode on SamplingStrategyResponse and on the four nested strategy types, since none of them had any. The double fields compare through Double.doubleToLongBits so the two NaN and ±0.0 cases behave.

It is also stricter than the byte comparison was: two responses that mean the same thing but arrive encoded differently now count as unchanged, where before they would have replaced the sampler.

unchangedStrategy_keepsSampler still fails if the cache is defeated and the module's check is green.

}

@Override
public boolean equals(@Nullable Object o) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This branch has not been deployed

No deployments
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.

2 participants