shashank created CAMEL-26882:
--------------------------------
Summary: camel-core - DefaultProducerCache: an AsyncProducer that
calls the callback and then throws completes the exchange twice
Key: CAMEL-26882
URL: https://issues.apache.org/jira/browse/CAMEL-26882
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: shashank
Assignee: shashank
Follow-up of CAMEL-26464, named in the description of its PR and asked for in
its review; the same on main.
{{DefaultProducerCache.doInAsyncProducer}} (used by {{toD}}, the routing slip,
{{to}} for a producer that is not optimised, and the async sends of the
producer template through {{asyncDispatchExchange}}) catches an exception
thrown by the producer, sets it on the exchange and calls
{{callback.done(true)}}. When the producer had already called the callback
before it threw (an {{AsyncProcessor}} that breaks the contract), the exception
is set on an exchange that has already been continued (maybe on another
thread), so a send that succeeded fails the exchange (with {{toD}} the steps
after it do not run), and the callback is called a second time: the error
handlers ignore that since CAMEL-26445, CAMEL-26461 and CAMEL-26464, but the
async sends of the producer template release the producer to the pool a second
time, so a producer of an endpoint that is not a singleton producer can be
handed to two sends at once. When the producer throws before it calls the
callback, the producer is not released to the pool (outside the async sends of
the producer template, where {{asyncDispatchExchange}} calls the callback).
The same happens in {{SendProcessor.sendUsingProducer}} and the sync
{{DefaultProducerCache.send}}; and with a send hook installed,
{{SendHelper.HookedSend}} (inside this path) sets the exception and calls
{{afterSend}} again before the producer cache sees it (left for a follow-up).
*Proposal*
Apply the exactly-once rule of CAMEL-26445, CAMEL-26461 and CAMEL-26464: the
callback of {{doInAsyncProducer}} completes once (a flag set by whoever
completes first); a throw after the callback is logged at WARN and not set on
the exchange; a throw before the callback completes the send as the callback
would (sent event, release of the producer, callback of the caller). Tests
where the producer calls the callback and then throws, and where it throws
before.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)