shashank created CAMEL-25123:
--------------------------------
Summary: 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-seda, camel-disruptor
Reporter: shashank
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)