[ 
https://issues.apache.org/jira/browse/CAMEL-25123?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen resolved CAMEL-25123.
---------------------------------
    Resolution: Fixed

Fixed by https://github.com/apache/camel/pull/27032 (merged to main, 4.23.0).

_Claude Code on behalf of davsclaus_

> camel-seda - a message that is discarded (discardWhenFull) or not added to a 
> full queue loses the on completions of its exchange, so a file consumer never 
> commits or rolls back the file
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25123
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25123
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-disruptor, camel-seda
>            Reporter: shashank
>            Priority: Minor
>
> For an InOnly exchange, {{SedaProducer.addToQueue}} creates a copy with 
> {{prepareCopy(exchange, true)}}, which hands the on completions of the 
> exchange over to the copy: the consumer's commit and rollback (such as the 
> file consumer's {{GenericFileOnCompletion}}), {{onCompletion}} 
> synchronizations, and the release of a spooled stream cache. The copy is then 
> added to the queue. When the copy is not added, it is dropped together with 
> those on completions, and they never run:
> * {{discardWhenFull=true}} and the queue is full: the copy is discarded, and 
> the exchange completes as a success.
> * the queue is full ({{Queue full}} {{IllegalStateException}}), the 
> {{offerTimeout}} elapses ({{Fails to insert element into queue}}), or the 
> producer is interrupted: the exchange fails, but its rollback does not run.
> The Disruptor producer has the same problem when the ring buffer is full with 
> {{blockWhenFull=false}} (the component default is {{true}}) or the Disruptor 
> is not started: {{DisruptorProducer}} hands the on completions over to the 
> copy before {{doPublish}} throws.
> Reproduced with a real file consumer, 
> {{from("file:in").to("seda:q?size=1&discardWhenFull=true")}} and a slow 
> consumer on {{seda:q}}, 4 files:
> {noformat}
> discardWhenFull:  1 consumed, 3 files left in the input directory, 
> in-progress repository size 3
> offerTimeout=50:  1 consumed, 3 files left in the input directory, 
> in-progress repository size 3
> size=1 (full):    1 consumed, 3 files left in the input directory, 
> in-progress repository size 3
> size=10 (control): 4 consumed, 4 files moved to .camel, in-progress 
> repository size 0
> {noformat}
> The files of the dropped copies are neither moved nor deleted, and as they 
> stay in the file consumer's in-progress repository, they are not picked up 
> again (not even after the queue has room again) until the route or the 
> application is restarted. With {{offerTimeout}} or a full queue, the exchange 
> failed, so the file should have been rolled back and retried.
> With stream caching spooled to disk, the spool file of every discarded copy 
> is also left behind until the context stops (a direct route with 4 spooled 
> messages to a full queue with {{discardWhenFull}}: 1 of 4 on completions of 
> the original exchanges ran, 3 spool files left).
> h3. Proposed fix
> When the copy is not added to the queue (discarded, or adding it failed), 
> hand its on completions back to the exchange 
> ({{target.getExchangeExtension().handoverCompletions(exchange)}}), so they 
> run when the exchange is done, with its outcome:
> * a discarded message completes as before as a success, so its consumer now 
> commits it (for example the file is moved to {{.camel}}), as for any message 
> whose route completed;
> * a message that could not be added fails as before, so its consumer now 
> rolls it back, and can pick it up again.
> The same in {{DisruptorProducer}} when {{doPublish}} fails. This also 
> releases the spool file of the copy.
> This differs from CAMEL-24950 (purging the queue), where the copy was 
> accepted by the queue and the exchange that sent it had already completed, so 
> the dropped copy runs the on completions as a failure itself.
> With the fix: discardWhenFull commits the 3 discarded files; offerTimeout and 
> a full queue roll back the files, which are retried and all 4 are consumed; 
> no spool file is left behind, and all on completions run. This changes what 
> happens to a discarded message, so it needs an upgrade guide note.
> Affected: all 4.x versions (the hand-over to the copy is long-standing).
> Duplicate check (2026-09-29): JIRA "discardWhenFull" (CAMEL-24948, the 
> interrupted paths, fixed on main), "offerTimeout" with "seda" (CAMEL-12584, 
> the option itself, and CAMEL-24948), "discard" with "onCompletion" and "seda" 
> (CAMEL-24950, the purge path, fixed). GitHub pull requests "discardWhenFull": 
> nothing on this.
> _Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to