How can I catch the final exception that caused the Camel failover load balancer to fail (e.g. to prepare a nice (HTTP) response instead of plain stack trace)?
I have something like this:
from("jetty:http://0.0.0.0:8081/context")
.process(frontendProcessor)
.loadBalance()
.failover(1,
false,
true,
true,
MyFancyException.class)
.to("direct:foo", "direct:bar")
.end()
.process(responseProcessor)
.stop();
with:
from("direct:foo")
.process(potentiallyThrowingMyFancyException);
(and exactly the same for "direct:bar)
Without the load balancing I'd go ahead and use onException
but I can't seem to get my head around how this works nicely with the load balancer and its internal exception handling. On the one hand, I would like to log the stack trace DURING load balancing and on the other hand I want to use onException
to create a nice error response - and ideally both within the same component/implementation.
So I tried this:
onException(Exception.class)
.process(myErrorProcessor)
.handled(true)
.stop();
from("jetty:http://0.0.0.0:8081/context")
.process(frontendProcessor)
.loadBalance()
.failover(1,
false,
true,
true,
MyFancyException.class)
.to("direct:foo", "direct:bar")
.end()
.process(responseProcessor)
.stop();
But handled(true)
seems to break the failover while on the other hand, I assume it's necessary when I use onException
for rendering the final HTTP error response.
How can I distinguish in an onException
error processor between:
an exception occured which triggers the failover, and
the failover load balancer failed entirely and you might want to create a nice final error response for the caller?
I ended up using the same approach as Laurent mentioned in his answer. I'll post the solution to have a complete example but accept his answer.
Please note the single but in my case significant addition to his answer, which is disabling the default error handler.
I had to do the following to achieve what I wanted:
doTry
+doCatch
with rethrow for debug loggingThe routes then look like this.
onException(Exception.class)
.process(myErrorProcessor)
.handled(true)
.stop();
from("jetty:http://0.0.0.0:8081/context")
.process(frontendProcessor)
.loadBalance()
.failover(1,
false,
true,
true,
MyFancyException.class)
.to("direct:foo", "direct:bar")
.end()
.process(responseProcessor)
.stop();
And this:
errorHandler(noErrorHandler());
from("direct:foo")
.doTry()
.process(potentiallyThrowingMyFancyException)
.doCatch(Exception.class)
.process(logAndRethrowProcessor)
.end();
(same for "direct:bar")
I'm more of a doTry...doCatch guy myself :-)
You can enclose your loadBalance EIP inside a doTry...doCatch and treat the final exception in there as you see fit. Same for the intermediate exceptions: use doTry...doCatch inside your from("direct:foo") and from("direct:bar") routes and operate on the caught exceptions as you like. Of course, don't forget to rethrow them afterwards.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With