Hello Claus, Thank you for your response. Yes, I understood that the observed behaviour is by-design in Camel.
Yet, as this does not fulfill our particular requirement, I wanted to know how to use Camel to behave differently. More specifically : we do need the firstRoute to continue the processing based on the fallback value of the secondRoute. ( as the result from secondRoute is not suitable for the original Camel caller and we don't want to change that : for the sake of separation of concern and reuse of the secondRoute in different context by other routes ) Sadly disabling errorhander in the secondRoute, won't help in that regard : we do need its redelivery support and we do want the secondRoute to provide a fallback value toward firstRoute (so it can continue its processing) Thank you for pointing out to onCompletion : it could be helpful sometimes but here, i don't think it is a good fit as it would mean duplicate the end of the firstRoute (or extracting it in yet another route to reuse) After some experimentation, I have succeeded to find a solution to do what we need in a way which does not seem too unnatural : By replacing : .to("direct:secondRoute") by .enrich("direct:secondRoute", new IgnoreErrorHandledEnrichStrategy()) with this custom AggregationStrategy : public class IgnoreErrorHandledEnrichStrategy implements AggregationStrategy { @Override public Exchange aggregate(Exchange original, Exchange enrichmentExchange) { if(enrichmentExchange.isFailed()) { // maintain error state is the exception was not handled : return enrichmentExchange; } else { // get the Body but (if set) not the "errorHandled" state of enrichmentExchange : original.getIn().setBody(enrichmentExchange.getIn().getBody()); // TODO copy header/properties/variables/ ... return original; } } } Would you recommend that ? or is there some better approach ? As another approach, would it be acceptable for you, if we test the value of Exchange.getExchangeExtension().getErrorHandlerHandled(); and reset it to null in custom AggregationStrategy ? Regards, -- Fabien ARRAULT <https://data.sigilium.com/signatures/rcgsp-rf-vea1joicbfrswihswyk8rc/link?element=name> On Fri, 14 Feb 2025 at 13:47, Claus Ibsen <claus.ib...@gmail.com> wrote: > Hi > > What Camel does is correct there was an exception and it was handled, and > you could build a custom response in the onException block as you did. And > then the routing stops and returns to the caller. > > The first route does not see the exception, so either you turn off error > handling in the second route, or make it return the proper response. Or you > can use onCompletion in the first route to change the response as you > desire. > > On Wed, Feb 12, 2025 at 3:06 PM Fabien Arrault < > farra...@consulting-for.d-edge.com> wrote: > > > Hello Raymond, > > > > The default Error Handler > > (org.apache.camel.processor.errorhandler.DefaultErrorHandler) is already > > fine to make the redeliveries and calling the exception policy without > > explicitly specifying it > > ( and I don't need the Deadletter capable error handler > > (org.apache.camel.processor.errorhandler.DeadLetterChannel) as my use > case > > is fully synchronous ) > > I did try though : and it doesn't change anything. > > > > Also, I do think that my issue is very specific to the use of a DIRECT > > channel between my two routes > > > > To make my requirement more clear, here a test case : the > > retryAndFallBack method > > shows the expected versus current behaviour : > > ( I also forbid to state that I am currently using Camel 4.7.0 ) > > > > @Slf4j > > public class TestCaseErrorHandling extends CamelTestSupport { > > > > record IntermediateResult(String val) {} > > > > @Override > > protected RoutesBuilder createRouteBuilder() { > > return new RouteBuilder() { > > @Override > > public void configure() throws Exception { > > from("direct:firstRoute").routeId("firstRoute") > > .onException(Exception.class).log("NEVER > > called here").end() > > .log(LoggingLevel.INFO,"firstRoute - BEGIN") > > .to("direct:secondRoute") > > .transform().simple("TRANSFORMED-${body.val}") > > // IntermediateResult to String > > .log(LoggingLevel.INFO,"firstRoute - END"); > > > > from("direct:secondRoute").routeId("secondRoute") > > // .errorHandler(defaultErrorHandler()) > > .onException(IOException.class) > > .handled(true) > > .maximumRedeliveries(3) > > .log("SecondRoute exception handler called > > for ${exception}") > > .transform().constant(new > > IntermediateResult("FALLBACK VALUE")) > > .end() > > .log(LoggingLevel.INFO,"secondRoute - BEGIN") > > .choice() > > .when(simple("${body} == 'pass'")) > > .transform().constant(new > > IntermediateResult("SOME REAL VALUE")).endChoice() > > .otherwise() > > .process( e -> { > > log.info("in failing processor"); > > throw new IOException("some > failure"); > > }) > > .end() > > .log(LoggingLevel.INFO,"secondRoute - END"); > > } > > }; > > } > > > > @Test > > public void pass() throws Exception { > > var resultBody = > template.requestBody("direct:firstRoute","pass"); > > assertThat(resultBody).isEqualTo("TRANSFORMED-SOME REAL > > VALUE"); // firstRoute Enriched the message > > } > > > > @Test > > public void retryAndFallBack() throws Exception { > > var resultBody = > template.requestBody("direct:firstRoute","error"); > > // Expected result : > > // assertThat(resultBody).isInstanceOf(String.class); > > // assertThat(resultBody).isEqualTo("TRANSFORMED-FALLBACK VALUE"); > > // Current result : > > assertThat(resultBody).isInstanceOf(IntermediateResult.class); > > assertThat(resultBody).isEqualTo(new > > IntermediateResult("FALLBACK VALUE")); > > } > > > > } > > > > Regards, > > Fabien > > > > On Wed, 12 Feb 2025 at 14:05, ski n <raymondmees...@gmail.com> wrote: > > > > > Did you try to use an errorHandler? Some like this: > > > > > > from("seda:a") > > > // here we configure the error handler > > > .errorHandler(deadLetterChannel("seda:error")) > > > // and we continue with the routing here > > > .to("seda:b"); > > > > > > Then you can set the errorHandler direct on the route (you can also add > > > redeliveries etc). Also check: > > > > > > https://camel.apache.org/manual/route-configuration.html > > > > > > In het routeConfiguration you can set specific error handler per route. > > > > > > Raymond > > > > > > > > > > > > > > > > > > > > > On Wed, Feb 12, 2025 at 12:00 PM Fabien Arrault < > > > farra...@consulting-for.d-edge.com> wrote: > > > > > > > Hello, > > > > > > > > In our application, we have factored out some common behaviour in a > > > direct: > > > > route called synchronously by other routes > > > > This sub-route needs to handle exception by first making retries ; > and > > > > then, when retry are exhausted, by returning **to the caller route** > a > > > > default intermediary response. > > > > > > > > Playing around with onException directive on this direct sub-route, I > > did > > > > not succeed to achieve the last part : > > > > * the retries do work correctly ( with required redelivery policy > > > > directive : maximumRedeliveries in particular ) > > > > * when retries are exhausted the custom exception policy is > correctly > > > > executed : it marks the exception as "handled" and set the body on > the > > > > exchange with the default intermediary response > > > > * BUT the processing of the exchange completely ends after that : > the > > > > parent route didn't continue its processing based on this > intermediary > > > > response > > > > * and in the ends the caller of the main route receives an > > intermediary > > > > response, which is not in the format it expects. > > > > > > > > I know there is doTry/doCatch directives, which would allow to > return a > > > > default response without involing errorHandler, but we can't use them > > > here > > > > as we also do need the redelivery behaviour of the default error > > handler. > > > > > > > > Digging a little into the camel source code, I understand that this > > > > behaviour is caused by the fact that both routes (main route / > > sub-route) > > > > are sharing the same Exchange when using direct: endpoint, > > > > and that in this case, the error handler of the sub-route flags the > > > > Exchange has errorHandlerHandled which caused BOTH routes to stop > their > > > > processing. > > > > > > > > > > > > I didn't succeed to find reference material on this specific > behaviour > > on > > > > direct endpoint. > > > > It seems to me to be a fairly reasonable requirement though. > > > > Is it possible to achieve what we need here ? > > > > > > > > Thanks in advance for your advices > > > > > > > > Regards, > > > > Fabien Arrault > > > > > > > > -- > > > > > > > > > > > > This e-mail, any attachments and the information contained therein > > ("this > > > > > > > > message") are confidential and intended solely for the use of the > > > > addressee(s). > > > > If you have received this message in error please send it > > > > back to the sender and > > > > delete it. Unauthorized publication, use, > > > > dissemination or disclosure of this > > > > message, either in whole or in part is > > > > strictly prohibited. > > > > > > > > > > > > > > > > > > > > Ce message électronique et tous les fichiers > > > > joints ainsi que les informations contenues dans ce message (ci-après > > "le > > > > message") sont confidentiels et destinés exclusivement à l'usage de > la > > > > personne à laquelle ils sont adressés. Si vous avez reçu ce message > par > > > > erreur, merci de le renvoyer à son émetteur et de le détruire. Toute > > > > diffusion, publication, totale ou partielle ou divulgation sous > quelque > > > > forme que ce soit non expressément autorisée de ce message, est > > > interdite. > > > > > > > > > > > -- > > > > > > This e-mail, any attachments and the information contained therein ("this > > > > message") are confidential and intended solely for the use of the > > addressee(s). > > If you have received this message in error please send it > > back to the sender and > > delete it. Unauthorized publication, use, > > dissemination or disclosure of this > > message, either in whole or in part is > > strictly prohibited. > > > > > > > > > > Ce message électronique et tous les fichiers > > joints ainsi que les informations contenues dans ce message (ci-après "le > > message") sont confidentiels et destinés exclusivement à l'usage de la > > personne à laquelle ils sont adressés. Si vous avez reçu ce message par > > erreur, merci de le renvoyer à son émetteur et de le détruire. Toute > > diffusion, publication, totale ou partielle ou divulgation sous quelque > > forme que ce soit non expressément autorisée de ce message, est > interdite. > > > > > -- > Claus Ibsen > ----------------- > @davsclaus > Camel in Action 2: https://www.manning.com/ibsen2 > -- This e-mail, any attachments and the information contained therein ("this message") are confidential and intended solely for the use of the addressee(s). If you have received this message in error please send it back to the sender and delete it. Unauthorized publication, use, dissemination or disclosure of this message, either in whole or in part is strictly prohibited. Ce message électronique et tous les fichiers joints ainsi que les informations contenues dans ce message (ci-après "le message") sont confidentiels et destinés exclusivement à l'usage de la personne à laquelle ils sont adressés. Si vous avez reçu ce message par erreur, merci de le renvoyer à son émetteur et de le détruire. Toute diffusion, publication, totale ou partielle ou divulgation sous quelque forme que ce soit non expressément autorisée de ce message, est interdite.