shashank created CAMEL-26601:
--------------------------------
Summary: camel-core - Recipient list in a doTry: a producer that
throws from process(exchange, callback), such as seda with a full queue, hangs
the exchange
Key: CAMEL-26601
URL: https://issues.apache.org/jira/browse/CAMEL-26601
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: shashank
Assignee: shashank
Follow-up of CAMEL-26464 (and CAMEL-26445, CAMEL-26446, CAMEL-26461): the same
hang for the one case none of them covers, a recipient of a recipient list
inside a {{doTry}}.
Found with a SPIN model of the multicast sub task, confirmed with tests on the
real classes.
Inside a {{doTry}}, {{MulticastProcessor.wrapInErrorHandler}} does not wrap a
recipient in an error handler: the recipient gets only the unit of work
processor. For a multicast the output is a channel, which catches a throw since
CAMEL-26464; for a recipient list the output is the producer of the recipient
endpoint. When that producer throws from {{process(exchange, callback)}}
instead of setting the exception on the exchange, the exception reaches the sub
task, the reactive executor drops it, and the recipient list never completes.
The caller waits for good (a {{ProducerTemplate.send}} never returns, a
consumer thread stays blocked). This happens with the default options and with
{{synchronous}}, {{parallelProcessing}}, {{stopOnException}} and
{{shareUnitOfWork}}. With a {{timeout}} the recipient list returns after the
timeout without the failure, so the {{doCatch}} does not run either. Outside a
{{doTry}} the error handler around the recipient handles it.
A producer in Camel itself does this: the seda producer throws
{{IllegalStateException: Queue full}} from {{process(exchange, callback)}} when
its bounded queue is full and neither {{blockWhenFull}} nor {{discardWhenFull}}
is set (the default, documented as "an exception will be thrown stating that
the queue is full"). Other component producers that throw from
{{process(exchange, callback)}} hang the same way.
{code:java}
from("direct:start")
.doTry()
.recipientList(constant("seda:work?size=1"))
.end()
.to("mock:result")
.endDoTry()
.doCatch(IllegalStateException.class)
.to("mock:caught")
.end();
template.sendBody("seda:work?size=1", "first"); // fills the queue (no
consumer yet)
template.sendBody("direct:start", "second"); // never returns; expected:
mock:caught gets it
{code}
*Proposal* (main only, it builds on CAMEL-26464)
* When the multicast does not wrap the output in an error handler, let its unit
of work processor catch the throw with the rule of CAMEL-26464
({{CamelInternalProcessor}} catchProcessorThrows): the copy is failed with the
exception, its unit of work is done (a copy with its own unit of work leaves
the inflight registry, and its completed or failed event fires), and the
multicast is continued exactly once, so the {{doCatch}} gets it. A catch in the
sub task itself would fix the hang but skip the unit of work of the copy.
* camel-seda should also set the exception instead of throwing when the queue
is full (a separate issue); this change is still needed for other producers
that throw.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)