CAMEL-24267: Synchronize writer-side setters in ThrottlingInflightRoutePolicy - #25161
Conversation
…tePolicy setMaxInflightExchanges and setResumePercentOfMax each read the other's field to recompute the ThrottlingLimits holder. Without synchronization, concurrent JMX callers can each read a stale value from the other setter, producing a holder built from a mixed snapshot. Synchronize both methods to ensure writer-side atomicity (JMX-invoked, so contention is negligible). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 553 tested, 29 compile-only — current: 553 all testedMaveniverse Scalpel detected 582 affected modules (current approach: 553).
|
gnodet
left a comment
There was a problem hiding this comment.
Review: Looks good ✅
Clean, well-justified follow-up to PR #24985 (CAMEL-24227). Adding synchronized to both JMX-writable setters correctly addresses the writer-side race condition where concurrent callers could each read a stale snapshot of the other's field, producing a ThrottlingLimits holder with inconsistent values. The test is thorough and CI is green.
Observations:
-
The production code change is minimal, correct, and well-scoped. The
synchronizedkeyword on both setters provides mutual exclusion so that each setter reads a consistent value of the other's field when recomputing theThrottlingLimitsholder. Combined with the existingvolatileon the holder reference (from CAMEL-24227), this gives a clean asymmetric synchronization pattern: writers exclude each other viasynchronized, while readers (throttle()) get visibility via the singlevolatileread of the immutable holder. -
The concurrency test using
CyclicBarrieris a well-known technique for verifying concurrent correctness. The 5,000-iteration loop with varyingmaxValandpctValprovides good coverage of different interleavings. The single-threaded and edge-case (clamping) tests are good supplementary coverage.
Minor nit: java.lang.reflect.Method is used as a fully qualified class name in the test body (lines 59, 113, 148) while java.lang.reflect.Field is properly imported. The project convention says to always add an import statement and use the simple class name. Consider adding import java.lang.reflect.Method;.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
| */ | ||
| package org.apache.camel.throttling; | ||
|
|
||
| import java.lang.reflect.Field; |
There was a problem hiding this comment.
Minor style nit: java.lang.reflect.Method is used as a FQCN in the test body (lines 59, 113, 148) while Field is properly imported here. Per project convention ("Do NOT use fully qualified class names"), consider adding:
| import java.lang.reflect.Field; | |
| import java.lang.reflect.Field; | |
| import java.lang.reflect.Method; |
There was a problem hiding this comment.
Good catch — fixed in 4770d50. Added import java.lang.reflect.Method and replaced all inline FQCNs with the simple name.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
gnodet
left a comment
There was a problem hiding this comment.
Review: Looks good ✅
Re-review after the FQCN fix commit — the import java.lang.reflect.Method was correctly added and all five FQCN usages replaced with the simple name across the three test methods. Clean fix, no other issues.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Summary
Claude Code on behalf of gnodet
setMaxInflightExchangesandsetResumePercentOfMaxto prevent concurrent JMX callers from producing aThrottlingLimitsholder with mixed stale values. Both setters read the other's field to recompute the resume limit — without synchronization, two concurrent callers can each read a stale snapshot, resulting in an inconsistent holder.ThrottlingInflightRoutePolicySetterTest) that hammers both setters from separate threads with aCyclicBarrierand verifies the invariant: the publishedThrottlingLimitsalways reflects a consistent(max, resume)pair.synchronizedis the simplest correct solution.JIRA: CAMEL-24267
Follow-up to: PR #24985 (CAMEL-24227) which fixed reader-side tearing but left writer-side atomicity unaddressed.
What changed
ThrottlingInflightRoutePolicy.javasynchronizedto both setter methodsThrottlingInflightRoutePolicySetterTest.javaTest plan
ThrottlingInflightRoutePolicySetterTestpasses (3 tests)ThrottlingInflightRoutePolicyTestpasses🤖 Generated with Claude Code