allthingssecurity opened a new pull request, #27032: URL: https://github.com/apache/camel/pull/27032
# Description [CAMEL-25123](https://issues.apache.org/jira/browse/CAMEL-25123) When the SEDA producer does not add an InOnly message to the queue, the on completions of the exchange never run. With a file consumer, the file is then neither committed nor rolled back, stays in the consumer's in-progress repository, and is not picked up again until a restart: ``` from("file:in").to("seda:q?size=1&discardWhenFull=true"); from("seda:q?size=1&discardWhenFull=true").delay(400).to("log:done"); 4 files: 1 consumed, 3 files left in "in" (not moved to .camel), in-progress repository size 3 ``` For an InOnly exchange, `SedaProducer.addToQueue` creates the copy with `prepareCopy(exchange, true)`, which hands the on completions of the exchange over to the copy (the file consumer's commit and rollback, `onCompletion` synchronizations, and the release of a spooled stream cache). When the copy is then not added to the queue, it is dropped together with them: - `discardWhenFull=true` and the queue is full: the exchange completes as a success, but the consumer never commits the message. - the queue is full (`Queue full`), the `offerTimeout` elapses, or the producer is interrupted: the exchange fails, but the consumer never rolls the message back, so it is not retried. - with stream caching spooled to disk, the spool file of the dropped copy is also left behind until the context stops. `DisruptorProducer` does the same when `doPublish` fails (the ring buffer is full with `blockWhenFull=false`, or the Disruptor is not started). This change: - `SedaProducer.addToQueue` hands the on completions of the copy back to the exchange (`target.getExchangeExtension().handoverCompletions(exchange)`) when the copy was not added to the queue, in a `finally`, so it covers the discard and every exception. The on completions then run when the exchange is done, with its outcome: a discarded message is committed, as the exchange completes as a success, and a message that could not be added is rolled back. The copy's own stream cache reference goes back with them, so its spool file is released. The enqueue branches moved unchanged into `offerToQueue`, which returns whether the copy was added. - `DisruptorProducer.process` does the same when `doPublish` throws for an InOnly exchange. - The InOut path (`copy=false`, the producer waits for the copy) is unchanged: nothing is handed over there. - Upgrade guide note for 4.23, as a discarded message is now committed by its consumer (for example the file is moved or deleted), where it used to stay in the input. This is the same kind of problem as CAMEL-24950 (the exchanges dropped by purging the queue), but there the queue had accepted the copy and the exchange that sent it had already completed, so the purge runs the on completions of the dropped copy as a failure itself. Here the copy never left the producer, so the on completions go back to the exchange and follow its outcome. Tests: - New `SedaQueueFullOnCompletionTest` (camel-core, where the seda tests live), with queues of size 1 that are full: `discardWhenFull` (the on completion of the discarded exchange runs `onComplete`), `offerTimeout` and a full queue (`onFailure`), a file consumer with `discardWhenFull` (the discarded file is moved to `.camel` at once, the queued one when the seda route runs), and a spooled stream with `discardWhenFull` (the spool directory is empty at the end). - New `DisruptorRingBufferFullOnCompletionTest` (camel-disruptor): a ring buffer of size 1 held by a blocked consumer, `blockWhenFull=false`: the second message fails and its on completion runs `onFailure`, and the first one completes when the consumer is released. - Without the change, all 5 seda tests fail (no on completion runs, the file stays in the input, a spool file is left behind), and the disruptor test fails (`expected: <[failure:B]> but was: <[]>`). - With the change: camel-core `org/apache/camel/component/seda/**,*Seda*,*StreamCach*,*Disruptor*,*WireTap*,*Multicast*`: 378 tests, 0 failures, 0 errors. camel-disruptor, all tests: 116 tests, 0 failures, 0 errors. This merges cleanly with main (including #26995, CAMEL-25094, in the same method). Found while reviewing the seda spool file fix (CAMEL-25094): a copy that `discardWhenFull` drops leaks its spool file, and the original exchange loses its on completions. I then reproduced it with a real file consumer as above, on main and with this change (discard: the 3 discarded files are committed; offerTimeout and a full queue: the 3 files are rolled back, retried, and all 4 are consumed; no spool file left, and all on completions run). # 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]
