简体   繁体   中英

Apache Camel - method shortcut to jump to aggregator when exception thrown in the middle of a multiple step split route

I'd like to ask if there is some way to skip rest of the split route and jump directly to aggregator part, when in the exception handler I mark the split route to continue.

I have a route like this:

  • receive a message
  • fetch config for 3 endpoints
  • merge config and message as a tuple for each endpoint, and create a list of it
  • .split() , and in the split route I convert message according to config for each endpoint( s1 ), fetch oauth token( s2 ), send to final endpoint with token( s3 ), collect response for each endpoint( s4 ), aggregate(split aggregator; splitting ends here, let's call it sa )
  • return as a whole one result
  • stop

You can see, in the split route there are 4 steps(s1-s4); if any of these step fails I want to jump to aggregation( sa ). For example, it does not make sense to continue the split route, if s1 or s2 fails.

I define an onException() clause to handle the exception and mark it to continue( continued(true) ),because anyway I want to reach aggregator. Also, if I mark continue(false) , not only split route, but the whole route(meaning the main route even before splitting) will be rolled back. I want to decide rollback after getting all the causes/exceptions in each split branch.

I have a workaround for a simple case, which is, in exception handler for errors in s2, I add a property in the exchange oauth_failed to be true , and add a condition check choice().when() after s2; if this prop is null, then go to s3 (continue sending). Solely for this purpose I must isolated s3 as a separate route( direct:s3 ).

.bean(S2Bean.class)
.choice()
    .when(simple("${exchangeProperty.oauth_failed} == null")) // null = continue the flow
        .to("direct:s3")
    .endChoice()
    // otherwise, it will skip s3 and s4, and jump to aggregator directly
.end()

But, what can I do if s1 throws exception? Do I need to isolate s2 as a direct endpoint too? Then each step in the pipeline should be a separate endpoint. I don't like that.

Find a solution: use doTry and doCatch in split route and don't .stop() .

from("direct:split")
    .doTry()
        .bean(S1Bean.class)
        .bean(S2Bean.class)
        .bean(S3Bean.class)
        .bean(S4Bean.class)
    .endDoTry()
    .doCatch(javax.ws.rs.ProcessingException.class) // oauth timeout
        .log(LoggingLevel.ERROR, "Time out, never retry, just aggregate")
        .bean(MyGenericExceptionHandler.class)
    .doCatch(Exception.class)
        .log(LoggingLevel.ERROR, "Other exceptions, mark as failed, aggregate")
        .bean(MyGenericExceptionHandler.class)
    .end();

And in the MyGenericExceptionHandler , exchange.getIn().setBody(xxx) to set body to the expected type which my aggregator needs. The exception is in exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class) , response code is null. (I create a dto to contain both status code and/or exception, so that either success or failure, I aggregate with same class)

Don't call stop() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM