allthingssecurity opened a new pull request, #26870: URL: https://github.com/apache/camel/pull/26870
# Description [CAMEL-25012](https://issues.apache.org/jira/browse/CAMEL-25012) With `onCompletion().parallelProcessing()`, `OnCompletionProcessor` submits the onCompletion of an exchange to its thread pool when the exchange's unit of work is done (`onComplete`, `onFailure`, and `onAfterRoute` in BeforeConsumer mode). The exchange then leaves the inflight repository. The graceful shutdown waits for the route's inflight exchanges, and for `ShutdownAware.getPendingExchangesSize()` of the route's services. But `OnCompletionProcessor` was not `ShutdownAware`, so the shutdown did not wait for the onCompletion tasks. It then shut the route down, and `OnCompletionProcessor.doShutdown()` called `shutdownNow()` on its pool: - queued onCompletion tasks were dropped; - running ones were interrupted. This happens when the context is stopped or the route is removed. A plain `stopRoute` does not shut the pool down, so the tasks keep running there, but the graceful wait is missing in that case too. For exchanges that had completed before the shutdown began, the onCompletion (sending a confirmation, releasing a reservation, ...) silently never ran. The shutdown was graceful and reported no timeout. In a reproduction with 40 completed exchanges and a 200 ms onCompletion, the graceful stop took 44 ms: 30 onCompletion tasks never ran, and the other 10 were interrupted. This change makes `OnCompletionProcessor` `ShutdownAware` like `WireTapProcessor`, and counts its tasks from submit, as #26851 (CAMEL-24995) now does for the Wire Tap: - it implements `ShutdownAware`, with `getPendingExchangesSize()` returning the number of onCompletion tasks from submit until they are done. `deferShutdown` returns `true` and `prepareShutdown` is a no-op, as in `WireTapProcessor`; - the counter is decremented when the task ends, or when the pool rejects it. The three submit sites now go through one helper. `doShutdown` still calls `shutdownNow`, which now only affects tasks that are still pending after the shutdown timeout, as for the Wire Tap. Tests: new `OnCompletionParallelProcessingShutdownTest`. An exchange completes, and Camel is stopped while its parallel onCompletion is still running. The onCompletion is released once the context is stopping (latches and Awaitility, no sleeps), and must complete. The test also checks that the running task counts as a pending exchange, and that none is pending afterwards. Without the fix: ``` AssertionFailedError: The onCompletion should be done ==> expected: <1> but was: <0> ``` (the onCompletion was interrupted by `shutdownNow`). With the fix it passes. `*OnCompletion*,*Shutdown*` in camel-core: 116 tests, 0 failures. Found with a TLA+ model of the onCompletion thread pool and the graceful shutdown, then reproduced against the real classes. With this change, "every completed exchange gets its onCompletion" and "a graceful shutdown does not interrupt an onCompletion" hold, and the shutdown terminates. The reproduction now gives 40 of 40 onCompletions finished and none interrupted, with a graceful stop of about 1 s. Known remaining window: the task is counted from submit, and the onCompletion synchronizations run last (`Ordered.LOWEST`), after the exchange has already left the route's inflight count. If another synchronization of the same exchange is slow (for example a remote file move or a transaction commit), a shutdown that checks in that gap sees neither an inflight exchange nor a pending task, and goes ahead. The same holds for the Wire Tap counter. Closing it would mean counting from when the synchronization is registered in `process()` and decrementing on every skip path; I kept this change to the same scope as #26851, but can do that here if you prefer. This does not conflict with #26851: that PR changes only `WireTapProcessor`, and both apply together. It is the same approach (count from submit, decrement on rejection), and the counter pattern could later be shared if the committers prefer. # 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. - [ ] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. (I built and tested the affected modules, including the formatter and import-sort plugins. I did not run the full root build.) # 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. This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a `Co-Authored-By` trailer. _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- 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]
