shashank created CAMEL-26459:
--------------------------------
Summary: camel-disruptor - multipleConsumers: when a consumer
fails, a consumer that gets to the message later routes an already failed copy
and never processes it
Key: CAMEL-26459
URL: https://issues.apache.org/jira/browse/CAMEL-26459
Project: Camel
Issue Type: Bug
Components: camel-disruptor
Reporter: shashank
Assignee: shashank
Found in the review of CAMEL-26458 (camel-disruptor, {{multipleConsumers}}: on
completions run twice).
With {{multipleConsumers=true}} each consumer routes its own copy of the
published exchange: {{DisruptorConsumer.prepareExchange}} copies the published
exchange when that consumer gets to the event. When a consumer fails,
{{MultipleConsumerSynchronizedExchange.consumed}} completes the exchange right
away (early completion) and copies the failure into the shared published
exchange first ({{ExchangeHelper.copyResults(getExchange(), result)}}). A
consumer that has not started on that event yet (its thread is still busy with
an earlier event) then copies an exchange that already has the exception, so
its route stops after the first step: that consumer never processes the
message, and nothing is logged as a failure of that consumer.
{code:java}
from("disruptor:fan?multipleConsumers=true") // consumer 1: fails m2 at
once
.filter(body().isEqualTo("m2")).throwException(new
IllegalArgumentException("Forced"));
from("disruptor:fan?multipleConsumers=true") // consumer 2: busy with m1
for a while
.process(e -> { /* slow for m1 */ })
.to("mock:c2"); // never gets m2
{code}
Reproduced with latches (no sleeps): consumer 2 waits on a latch while routing
m1; consumer 1 fails m2 and the caller's on completion reports the failure of
m2; then consumer 2 is released: it routes m1 and never m2 (its copy of m2
already has the exception, so its route stops before {{mock:c2}}). A SPIN model
of the two consumers (the published exchange written by the early completion,
copied later by the other consumer) shows the same order, and that running the
early completion on a copy of the published exchange keeps the copies clean.
The early completion also runs the on completions of the caller's exchange
(such as the rollback of a file consumer: read lock and in-progress mark
released) while the other consumers are still routing the message, so the
source may hand the same message out again meanwhile. camel-seda completes the
exchange of {{multipleConsumers}} once, after all consumers are done.
With a waiting producer (InOut) the producer has already been answered by then,
so a late consumer skips the message (the copy is marked to be ignored) instead
of routing a failed copy.
Same on main before and after CAMEL-26458.
*Proposal* (to discuss): either complete the exchange once when all consumers
are done (as seda; a waiting producer then gets the failure when all consumers
are done, bounded by its timeout), or keep the early completion but run it on a
copy of the published exchange, so that the published exchange is not written
after it was published and later consumers copy the message as it was sent.
Tests: a consumer that is busy with an earlier message when another consumer
fails the next one still routes it.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)