CAMEL-23352: Add syncOptimisticRetry option to Aggregate EIP#22769
Conversation
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
when you add new options to EIPs you generally need to rebuild the entire code base |
|
for example run from root |
gnodet
left a comment
There was a problem hiding this comment.
Review: CAMEL-23352 — Add syncOptimisticRetry option to Aggregate EIP
Thank you for this contribution! The use case is well-motivated — async optimistic locking retries breaking transaction context is a real problem, and adding an opt-in synchronous retry is a clean approach. The core implementation logic is correct.
A few items need attention before this can merge.
Blocker: Missing generated files
The PR modifies 4 hand-written files but does not include any regenerated downstream artifacts. CI will fail at the "Fail if there are uncommitted changes" step. Please run:
mvn install -B -pl core/camel-core-model -DskipTestsThen check git status and commit all generated file changes. This will update at minimum:
core/camel-core-model/src/generated/— JSON model metadata, configurersdsl/camel-yaml-dsl/— YAML DSL schema and deserializers
The auto-generated options table in the aggregate EIP docs (aggregate-eip.adoc) will also pick up the new option from the Javadoc after regeneration, so a separate prose change is likely not needed.
Implementation
The core retry logic is sound:
- The
syncOptimisticRetrybranch correctly callsdoDelay(attempt)thencontinues the retry loop on the calling thread. InterruptedExceptionhandling correctly restores the interrupt flag and propagates viaexchange.setException().- Default (
false) preserves existing async behavior — no regression risk. - The reifier and copy constructor correctly wire the new option.
See inline comments for minor suggestions.
Claude Code on behalf of Guillaume Nodet
|
Thanks for the review! I've addressed your feedback in the latest push:
Let me know if there's anything else to adjust |
| sender.start(); | ||
|
|
||
| // Let at least one retry attempt happen before interrupting | ||
| Thread.sleep(100); |
There was a problem hiding this comment.
Can you use Awaitility instead of this Thread.sleep?
|
There are some uncommitted changes: |
|
@code-massel can you do a full rebuild and add the modified files to this PR mvn clean install -P fastinstall from the root folder |
gnodet
left a comment
There was a problem hiding this comment.
Second Review: CAMEL-23352 — optimisticLockingSyncRetry option for Aggregate EIP
Claude Code on behalf of Guillaume Nodet
Thank you for addressing the first round of feedback — the rename to optimisticLockingSyncRetry, the improved Javadoc, and the two additional tests (nonzero delay + interrupt path) are all solid improvements. The core implementation in AggregateProcessor.doInOptimisticLock() looks correct: the synchronous doDelay() + continue path cleanly preserves the calling thread, and the InterruptedException handling is done properly with Thread.currentThread().interrupt().
This second round focuses on the test class, specifically around style conventions and test robustness.
Summary of Findings
| # | Severity | Finding |
|---|----------|---------||
| 1 | Must fix | Thread.sleep(100) in testSyncRetryInterrupted — use Awaitility (project rule, also flagged by @Croway) |
| 2 | Must fix | Conditional assertions silently pass — if (aggregateThreadName != null) and if (result != null && ...) mean the test can succeed without ever verifying the core behavior |
| 3 | Should fix | Test class and methods are public — newer tests in this package use package-private (see OptimisticLockRetryPolicyTest, AggregateCompletionOnlyTwoTest) |
| 4 | Should fix | Unused variable callerThread in testSyncRetryHappensInSameThread |
See inline comments for details and suggested fixes.
This review covers project conventions and test quality. It does not replace specialized tools (CodeRabbit, SonarCloud, etc.).
gnodet
left a comment
There was a problem hiding this comment.
Second Review: CAMEL-23352 — optimisticLockingSyncRetry option for Aggregate EIP
Claude Code on behalf of Guillaume Nodet
Thank you for addressing the first round of feedback — the rename to optimisticLockingSyncRetry, the improved Javadoc, and the two additional tests (nonzero delay + interrupt path) are all solid improvements. The core implementation in AggregateProcessor.doInOptimisticLock() looks correct: the synchronous doDelay() + continue path cleanly preserves the calling thread, and the InterruptedException handling is done properly with Thread.currentThread().interrupt().
This second round focuses on the test class, specifically around style conventions and test robustness.
Summary of Findings
| # | Severity | Finding |
|---|---|---|
| 1 | Must fix | Thread.sleep(100) in testSyncRetryInterrupted — use Awaitility (project rule, also flagged by @Croway) |
| 2 | Must fix | Conditional assertions silently pass — if (aggregateThreadName != null) and if (result != null && ...) mean the test can succeed without ever verifying the core behavior |
| 3 | Should fix | Test class and methods are public — newer tests in this package use package-private (see OptimisticLockRetryPolicyTest, AggregateCompletionOnlyTwoTest) |
| 4 | Should fix | Unused variable callerThread in testSyncRetryHappensInSameThread |
See inline comments for details and suggested fixes.
This review covers project conventions and test quality. It does not replace specialized tools (CodeRabbit, SonarCloud, etc.).
gnodet
left a comment
There was a problem hiding this comment.
Second Review: CAMEL-23352 — optimisticLockingSyncRetry option for Aggregate EIP
Claude Code on behalf of Guillaume Nodet
Thank you for addressing the first round of feedback — the rename to optimisticLockingSyncRetry, the improved Javadoc, and the two additional tests (nonzero delay + interrupt path) are all solid improvements. The core implementation in AggregateProcessor.doInOptimisticLock() looks correct: the synchronous doDelay() + continue path cleanly preserves the calling thread, and the InterruptedException handling is done properly with Thread.currentThread().interrupt().
This second round focuses on the test class, specifically around style conventions and test robustness.
Summary of Findings
| # | Severity | Finding |
|---|---|---|
| 1 | Must fix | Thread.sleep(100) in testSyncRetryInterrupted — use Awaitility (project rule, also flagged by @Croway) |
| 2 | Must fix | Conditional assertions silently pass — if (aggregateThreadName != null) and if (result != null && ...) mean the test can succeed without ever verifying the core behavior |
| 3 | Should fix | Test class and methods are public — newer tests in this package use package-private (see OptimisticLockRetryPolicyTest, AggregateCompletionOnlyTwoTest) |
| 4 | Should fix | Unused variable callerThread in testSyncRetryHappensInSameThread |
See inline comments for details and suggested fixes.
This review covers project conventions and test quality. It does not replace specialized tools (CodeRabbit, SonarCloud, etc.).
|
Thanks for the second round of feedback — all items addressed and pushed (10bd777). Test class fixes:
Missing generated file:
All 4 tests pass locally. Let me know if there is anything else to address. |
|
Sorry but its safer to do a full rebuild when you change EIPs or whatnot as it affect other DSLs, catalog etc There are uncommitted changes |
When optimisticLocking is enabled, retries are normally scheduled asynchronously on a background ScheduledExecutorService, which switches threads and breaks transactional use cases where the aggregation repository and inbound message store must commit/rollback within a single transaction boundary. The new syncOptimisticRetry flag (default false) causes the retry delay to execute via Thread.sleep on the calling thread instead, preserving the transaction context. This restores the Camel 2.x behavior for users who need it, without changing the default async behavior.
Rename syncOptimisticRetry → optimisticLockingSyncRetry for consistency with the existing optimisticLocking option naming. Update Javadoc to note the flag only takes effect when optimisticLocking() is enabled. Add tests for non-zero retry delay and thread interruption scenarios. Regenerate catalog metadata.
- Remove public modifiers from class and all test methods (package-private convention) - Remove unused callerThread variable in testSyncRetryHappensInSameThread - Replace conditional if-assertions with assertNotNull + direct assertions - Replace Thread.sleep(100) with Awaitility.await() in testSyncRetryInterrupted
…ncRetry File was added to main after branch was created. Regenerated after rebasing onto main; includes the new optimisticLockingSyncRetry option.
Restore 16 files where the build corrupted Unicode characters (en-dash, smart quotes, ❌, ✅) to replacement sequences due to missing UTF-8 encoding during generation.
When optimisticLocking is enabled, retries are normally scheduled asynchronously on a background ScheduledExecutorService, which switches threads and breaks transactional use cases where the aggregation repository and inbound message store must commit/rollback within a single transaction boundary.
The new syncOptimisticRetry flag (default false) causes the retry delay to execute via Thread.sleep on the calling thread instead, preserving the transaction context. This restores the Camel 2.x behavior for users who need it, without changing the default async behavior.
Description
When
optimisticLockingis enabled on the Aggregate EIP, retry failures are scheduled asynchronously on a backgroundScheduledExecutorService. This thread switch breaks transactional use cases where the aggregation repository and inbound message store must commit/rollback within a single transaction boundary (transaction context is bound to the originating thread).This PR adds a new
syncOptimisticRetryoption (defaultfalse) to theaggregateEIP. When enabled, the retry delay runs viaThread.sleepon the calling thread instead of scheduling on a background executor, preserving the transaction context. Default isfalseso existing routes are unaffected.Target
mainbranch)Tracking
Apache Camel coding standards and style
I checked that each commit in the pull request has a meaningful subject line and body.
I have run
mvn clean install -DskipTestslocally from root folder and I have committed all auto-generated changes.