Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle failover load balancer failure in Camel?

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:

  1. an exception occured which triggers the failover, and

  2. the failover load balancer failed entirely and you might want to create a nice final error response for the caller?

like image 264
ahor Avatar asked Apr 09 '18 11:04

ahor


2 Answers

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:

  1. Leave main route with load balancer as is
  2. Deactivate default error handler in the sub routes
  3. Use doTry+doCatch with rethrow for debug logging

The 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")

like image 64
ahor Avatar answered Nov 01 '22 23:11

ahor


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.

like image 32
Laurent Chabot Avatar answered Nov 01 '22 21:11

Laurent Chabot