ammachado opened a new pull request, #29129: URL: https://github.com/apache/camel/pull/29129
# Description [CAMEL-26557](https://issues.apache.org/jira/browse/CAMEL-26557), a sub-task of CAMEL-25132. ## The problem With virtual threads, a parallel split or multicast whose thread pool uses the `Abort` rejected policy runs **one item fewer at a time** than `maxQueueSize` allows. With `maxQueueSize` 1 it is **rejected** after `keepAliveTime`. The dispatcher of the split (`MulticastReactiveTask`) runs in the `BoundedExecutorService` and submits itself again for each item while it holds a permit. CAMEL-26478 (#28823) made a task of the executor run nested work inline when no permit is free, but deliberately not with `Abort`. So with `Abort`, the dispatcher still waits for a permit while holding one, and one permit always belongs to the dispatcher. Measured with a parallel split of 10 items of 300 ms, peak items running at once for `maxQueueSize` 1 / 2 / 3: | policy | virtual threads, before | platform threads (pool size 2) | |---|---|---| | `CallerRuns` | 1 / 2 / 3 | 2 / 2 / 2 | | `Block` | 1 / 2 / 3 | 2 / 2 / 2 | | `Abort` | **rejected after `keepAliveTime` / 1 / 2** | rejected at once / 2 / 2 | `SplitterParallelAsyncProcessorIssueTest` failed in virtual thread mode because of this: 5.2 s instead of 2.7 s. ## The change A task of the executor runs nested work inline **whatever the policy**. That means removing the `Abort` condition in `BoundedExecutorService.execute`. **This reverses a decision of #28823**, which kept `Abort` waiting so that "nothing is lost silently". Why I think it should go: - A nested submission waits while it holds a permit, so the wait can only end in reduced parallelism or a timeout. - Inline work is not lost: it runs, on a thread that already holds a permit. The concurrency limit holds, apart from the hand-off past the depth limit that #28823 already documents. - A submitter **outside** the executor still waits and is rejected with `Abort` (`testAbortOnTimeout`), so backpressure does not change. - One difference to know about: with `Abort` and `maxQueueSize` 1, a parallel split now succeeds with virtual threads, where with platform threads it is still rejected. It is more lenient, not stricter. Changing `MulticastProcessor` instead does not work. The dispatcher starts on the pool (`doProcess`), so it would hold a permit however it loops over the items. And with platform threads, submitting the items in a loop fills the `ThreadPoolExecutor` queue, so `Abort` would reject an item that is accepted today. ## Tests - `BoundedExecutorServiceTest`: - `testNestedTaskIsStillRejectedWithAbortPolicy` is replaced by `testNestedTaskRunsInlineWithAbortPolicy`, which covers the single-permit case. - New: `testNestedTaskRunsInlineWithAbortPolicyWhenOtherTasksHoldThePermits`, the split's case. - Both fail before the change, timing out on the wait. - `SplitterParallelAsyncProcessorIssueTest` counted distinct thread names, which grow with the number of tasks when every task gets a new virtual thread. It now asserts that **exactly 2** items run at once: - more than 2 would mean the CAMEL-21671 regression (an async processor letting every item start); - fewer than 2 means this bug. It fails with the old code in virtual mode (`expected: <2> but was: <1>`). ## Second commit: tests that work with virtual threads I ran each test that is skipped with virtual threads in virtual mode, with the skip turned off (`junit.jupiter.conditions.deactivate`): - `ManagedRouteRemoveWireTapTest` passes, so it is no longer skipped. - `DefaultExecutorServiceManagerTest` skipped the whole class, although only 12 of its 30 methods expect a `ThreadPoolExecutor`. The skip now sits on those 12, so 18 more methods run with virtual threads. - `WireTapAbortPolicyTest` stays skipped: its pool has `maxQueueSize` 0, which means no limit with virtual threads. The skip reason now says that. - The rest (`ThreadsKeepAliveTimeTest`, the five `Managed*ThreadPool*Test`, `AggregateTimeoutWithNoExecutorServiceTest`) need a `ThreadPoolExecutor`, its JMX attributes or a thread per pool, and stay skipped. ## Verified - `camel-util`: full suite, 335 tests, 0 failures. - `camel-support`: full suite, including its virtual threads execution (157 + 5), 0 failures. - `camel-core`: every split, multicast, thread, recipient list, wire tap, parallel and aggregate test, 991 tests, with and without `-Dcamel.threads.virtual.enabled=true`, 0 failures. The skips are the existing manual, load and virtual-only tests. - The three tests changed in the second commit, in both modes, with the skips active. Not verified: the full `camel-core` suite, and `-Psourcecheck` (the formatter and impsort were run). ## Docs `threading-model.adoc`, and the 4.24 upgrade guide entry of CAMEL-26478, amended rather than duplicated since 4.24.0 is not released. The 4.22.x port of CAMEL-26478 (#28996) does not include this change; whether to backport it is up to the maintainers. # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [x] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for the change (usually before you start working on it). # Apache Camel coding standards and style - [x] I checked that each commit in the pull request has a meaningful subject line and body. - [x] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. (Run on the changed modules, `core/camel-util`, `core/camel-core` and `core/camel-management`, not on the whole tree. `git status` was clean afterwards.) # AI-assisted contributions - [x] If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR description identifies the AI tool used. 🤖 Generated with [Claude Code](https://claude.com/claude-code) on behalf of Adriano Machado (@ammachado) _This was generated by an AI agent and may contain inaccuracies. Please verify before relying on it._ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
