You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Idle Q2 instances can accumulate humongous Prometheus scrape allocations in Old Gen, expose an oversized TM operation histogram, and let the always-on JFR repository grow without bounds.
Why This Change Was Made
stream Prometheus exposition directly to the HTTP response using chunked transfer encoding instead of building and copying a large String
disable Micrometer's automatic percentile histogram for jpos.tm.op, retaining the six explicit SLO buckets
cap the default JFR recording at 250 MiB and four hours
encode the small status response once with UTF-8
User Impact
Prometheus scrapes no longer create repeated full-payload byte arrays, TM-bearing instances expose a substantially smaller metrics document, and Q2's default JFR repository remains bounded during long uptimes.
Non-blocking observation on testTMOperationHistogramUsesOnlyServiceLevelObjectives: it asserts through the process-global registry. Q2.meterRegistry is Metrics.globalRegistry, and every Q2 constructed anywhere in the test JVM runs registerMicroMeter(), which clear()s that shared registry and stacks one more copy of the TM_OPERATION filter plus one more PrometheusMeterRegistry member onto it. The test passes today because the timer is registered and scraped inside one method, but it turns order-sensitive the moment another test constructs a Q2 between registration and assertion (several tests in Q2Test do construct extra instances), or registers a conflicting jpos.tm.op meter.
Two levels of improvement:
Test-local hardening (cheap, could go in this PR): tag the timer with a unique per-run value (e.g. a UUID) and remove the meter in a finally, so nothing leaks into the shared registry for later tests.
Actual fix (follow-up material, not this PR): give each Q2 instance its own CompositeMeterRegistry instead of mutating Metrics.globalRegistry from the constructor path. That makes registerMicroMeter() idempotent per instance, stops filter/member accumulation when multiple Q2s live in one JVM (embedded users, not just tests), and lets tests assert against a fully isolated registry.
Addressed in 2688018. The regression test now uses a per-run UUID tag and removes its timer from the shared registry in a finally, avoiding collisions and meter leakage between tests.
I kept per-Q2 registry ownership out of this PR as suggested; that broader change needs a separate compatibility and lifecycle discussion.
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
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.
What Problem This Solves
Idle Q2 instances can accumulate humongous Prometheus scrape allocations in Old Gen, expose an oversized TM operation histogram, and let the always-on JFR repository grow without bounds.
Why This Change Was Made
Stringjpos.tm.op, retaining the six explicit SLO bucketsUser Impact
Prometheus scrapes no longer create repeated full-payload byte arrays, TM-bearing instances expose a substantially smaller metrics document, and Q2's default JFR repository remains bounded during long uptimes.
Evidence
./gradlew :jpos:test --tests org.jpos.q2.Q2Test --no-daemon./gradlew :jpos:test --no-daemon+InfFixes #755