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)

Reply via email to