shashank created CAMEL-26430:
--------------------------------
Summary: camel-core - RedeliveryErrorHandler: a redelivery whose
processor throws hangs the exchange (RedeliveryTask.redeliver has no try/catch)
Key: CAMEL-26430
URL: https://issues.apache.org/jira/browse/CAMEL-26430
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: shashank
Assignee: shashank
Follow-up of CAMEL-26327 (apache/camel#28750), asked for in its review.
{{RedeliveryErrorHandler.RedeliveryTask.run()}} wraps its work in a try/catch:
an unexpected exception is set on the exchange, the task is released and the
callback is called, so the exchange completes (failed).
{{RedeliveryTask.redeliver()}} has no such guard. It runs as a task of its own
on the reactive executor:
* {{reactiveExecutor.schedule(this::redeliver)}} for an immediate redelivery
and after a synchronous redelivery delay ({{runSynchronousRedelivery}}),
* {{executorService.schedule(() -> reactiveExecutor.schedule(this::redeliver),
redeliveryDelay, ...)}} for an asynchronous delayed redelivery.
If anything in {{redeliver()}} throws, for example an {{AsyncProcessor}} (or a
step hook) whose {{process(exchange, callback)}} throws instead of setting the
exception on the exchange, or a failure in {{prepareExchangeForRedelivery}} /
{{deliverToOnRedeliveryProcessor}}, the exception reaches
{{DefaultReactiveExecutor}}, which logs it ({noformat}Error executing reactive
work due to ... This exception is ignored.{noformat}) and drops it. The
callback of the exchange is never called, so the caller waits forever (a
synchronous {{template.send}} or a consumer thread blocks; an async caller
never completes). The first delivery does not hang in the same case, because
{{run()}} catches it.
This is the general reason why a processor that throws on redelivery hangs
instead of failing: CAMEL-26327 (a routing slip whose step had lost its
producer threw an NPE on redelivery) and CAMEL-26301 (the tokenizer) had the
same symptom.
*Proposal*
* Give {{redeliver()}} the same guard as {{run()}}: catch the exception, set it
on the exchange, release the task and call the callback (or loop back through
{{reactiveExecutor.schedule(this)}} so the error handler sees the new failure,
as when the onRedelivery processor fails). Which of the two is a decision for
the fix: looping back lets the error handler handle or redeliver the new
failure, the direct callback matches {{run()}}.
* A test with an {{AsyncProcessor}} that throws from {{process(exchange,
callback)}} on the second call, with immediate, synchronous delayed and
asynchronous delayed redelivery: the send must complete (failed or handled)
instead of hanging.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)