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]

Reply via email to