This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-14182 in repository https://gitbox.apache.org/repos/asf/camel.git
commit d1c3073d32d47f4c600e8e1a27fc6fff29c7b311 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Nov 15 10:26:36 2019 +0100 CAMEL-14182: Make Hystrix EIP general as Circuit Breaker EIP and allow to plugin other implementations. WIP --- .../src/main/docs/eips/hystrix-eip.adoc | 115 ++++++++++++++------- .../src/main/docs/eips/onFallback-eip.adoc | 17 +-- .../camel/main/MainConfigurationProperties.java | 2 +- .../src/main/java/sample/camel/ClientRoute.java | 2 +- .../HystrixHierarchicalConfiguration.java | 5 +- .../HystrixHierarchicalConfigurationTest.java | 10 +- .../processor/HystrixMultiConfiguration.java | 9 +- .../processor/HystrixMultiConfigurationTest.java | 1 - 8 files changed, 105 insertions(+), 56 deletions(-) diff --git a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc index f398fd5..3fa4d1b 100644 --- a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc +++ b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc @@ -5,6 +5,9 @@ The Hystrix EIP provides integration with Netflix https://github.com/Netflix/Hystrix[Hystrix] to be used as circuit breaker in the Camel routes. Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable. +NOTE: Camel provides the Circuit Breaker EIP in the route model, which allows to plugin different implementations. +Hystrix is one such implementation. + Maven users will need to add the following dependency to their pom.xml to use this EIP: [source] @@ -29,38 +32,7 @@ The Hystrix EIP supports 2 options which are listed below: |=== // eip options: END -== Camel's Error Handler and Hystrix EIP - -By default the Hystrix EIP handles errors by itself. This means if the circuit breaker is open and -the message fails, then Camel's error handler is not reacting also. -However, you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown: - -[source,java] ----- -// Camel's error handler that will attempt to redeliver the message 3 times -errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDelay(0)); - -from("direct:start") - .to("log:start") - // turn on Camel's error handler on hystrix so it can do redeliveries - .hystrix().inheritErrorHandler(true) - .to("mock:a") - .throwException(new IllegalArgumentException("Forced")) - .end() - .to("log:result") - .to("mock:result"); ----- - -This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded -to always fail by throwning an exception. Because the `inheritErrorHandler` has been enabled, -then Camel's error handler will attempt to call the Hystrix EIP block again. - -That means the `mock:a` endpoint will receive the message again, and a total of 1 + 3 = 4 message -(first time + 3 redeliveries). - -If we turn off the `inheritErrorHandler` option (default) then the Hystrix EIP will only be -executed once because it handled the error itself. - +See xref:hystrixConfiguration-eip.adoc[Hystrix Configuration] for all the configuration options on Hystrix EIP. == Samples @@ -68,7 +40,7 @@ Below is an example route showing an Hystrix endpoint that protects against slow [source,java] ---- from("direct:start") - .hystrix() + .circuitBreaker() .to("http://fooservice.com/slow") .onFallback() .transform().constant("Fallback message") @@ -82,21 +54,94 @@ And in XML DSL: <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:start"/> - <hystrix> + <circuitBreaker> <to uri="http://fooservice.com/slow"/> <onFallback> <transform> <constant>Fallback message</constant> </transform> </onFallback> - </hystrix> + </circuitBreaker> <to uri="mock:result"/> </route> </camelContext> ---- +== Configuring Hystrix + +You can fine-tune Hystrix by the many xref:hystrixConfiguration-eip.adoc[Hystrix Configuration] options. +For example to use a 2 second execution timeout, you can do as follows: + +[source,java] +---- +from("direct:start") + .circuitBreaker() + // use 2 second timeout + .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end() + .log("Hystrix processing start: ${threadName}") + .toD("direct:${body}") + .log("Hystrix processing end: ${threadName}") + .end() + .log("After Hystrix ${body}"); +---- + +And in XML: + +[source,xml] +---- +<route> + <from uri="direct:start"/> + <circuitBreaker> + <hystrixConfiguration executionTimeoutInMilliseconds="2000"/> + <log message="Hystrix processing start: ${threadName}"/> + <toD uri="direct:${body}"/> + <log message="Hystrix processing end: ${threadName}"/> + </circuitBreaker> + <log message="After Hystrix: ${body}"/> +</route> +---- + +== Fallback + See xref:onFallback-eip.adoc[onFallback]. == Other examples You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-hystrix[camel-example-hystrix]. + +== Using Hystrix with Spring Boot + +See the xref:hystrix-component.adoc[Hystrix Component]. + +== Camel's Error Handler and Hystrix EIP + +By default the Hystrix EIP handles errors by itself. This means if the circuit breaker is open and +the message fails, then Camel's error handler is not reacting also. +However, you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown: + +[source,java] +---- +// Camel's error handler that will attempt to redeliver the message 3 times +errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDelay(0)); + +from("direct:start") + .to("log:start") + // turn on Camel's error handler on hystrix so it can do redeliveries + .circuitBreaker().inheritErrorHandler(true) + .to("mock:a") + .throwException(new IllegalArgumentException("Forced")) + .end() + .to("log:result") + .to("mock:result"); +---- + +This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded +to always fail by throwing an exception. Because the `inheritErrorHandler` has been enabled, +then Camel's error handler will attempt to call the Hystrix EIP block again. + +That means the `mock:a` endpoint will receive the message again, and a total of 1 + 3 = 4 message +(first time + 3 redeliveries). + +If we turn off the `inheritErrorHandler` option (default) then the Hystrix EIP will only be +executed once because it handled the error itself. + diff --git a/core/camel-core-engine/src/main/docs/eips/onFallback-eip.adoc b/core/camel-core-engine/src/main/docs/eips/onFallback-eip.adoc index 8a282d7..bc083e4 100644 --- a/core/camel-core-engine/src/main/docs/eips/onFallback-eip.adoc +++ b/core/camel-core-engine/src/main/docs/eips/onFallback-eip.adoc @@ -1,9 +1,9 @@ [[onFallback-eip]] = On Fallback EIP -If you are using *onFallback* then that is intended to be local processing only where you can do a message transformation or call a bean or something as the fallback. If you need to call an external service over the network then you should use *onFallbackViaNetwork* that runs in another independent *HystrixCommand* that uses its own thread pool to not exhaust the first command. -Configuring Hystrix Example -Hystrix has many options as listed in the table above. For example to set a higher timeout to *5* seconds, and also let the circuit breaker wait *10* seconds before attempting a request again when the state was tripped to be open. +If you are using *onFallback* then that is intended to be local processing only where you can do a message transformation or call a bean or something as the fallback. + +If you need to call an external service over the network then you should use *onFallbackViaNetwork* that runs in another independent *HystrixCommand* that uses its own thread pool to not exhaust the first command. == Options @@ -17,10 +17,13 @@ The On Fallback EIP supports 1 options which are listed below: |=== // eip options: END +Hystrix has many options as listed in xref:hystrixConfiguration-eip.adoc[Hystrix Configuration]. +For example to set a higher timeout to *5* seconds, and also let the circuit breaker wait *10* seconds before attempting a request again when the state was tripped to be open. + [source,java] ---- from("direct:start") - .hystrix() + .circuitBreaker() .hystrixConfiguration() .executionTimeoutInMilliseconds(5000) .circuitBreakerSleepWindowInMilliseconds(10000) @@ -38,7 +41,7 @@ And in XML DSL: <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:start"/> - <hystrix> + <circuitBreaker> <hystrixConfiguration executionTimeoutInMilliseconds="5000" circuitBreakerSleepWindowInMilliseconds="10000"/> <to uri="http://fooservice.com/slow"/> @@ -47,7 +50,7 @@ And in XML DSL: <constant>Fallback message</constant> </transform> </onFallback> - </hystrix> + </circuitBreaker> <to uri="mock:result"/> </route> </camelContext> @@ -66,7 +69,7 @@ You can also configure Hystrix globally and then refer to that configuration: <route> <from uri="direct:start"/> - <hystrix hystrixConfigurationRef="sharedConfig"> + <circuitBreaker configurationRef="sharedConfig"> <to uri="http://fooservice.com/slow"/> <onFallback> <transform> diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java index 02de495..433b18d 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java @@ -41,7 +41,7 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< // -------------------------------------------------------------- /** - * To configure Hystrix EIP + * To configure Circuit Breaker EIP with Hystrix */ public HystrixConfigurationProperties hystrix() { return hystrixConfigurationProperties; diff --git a/examples/camel-example-hystrix/client/src/main/java/sample/camel/ClientRoute.java b/examples/camel-example-hystrix/client/src/main/java/sample/camel/ClientRoute.java index 18013b3..4f72e30 100644 --- a/examples/camel-example-hystrix/client/src/main/java/sample/camel/ClientRoute.java +++ b/examples/camel-example-hystrix/client/src/main/java/sample/camel/ClientRoute.java @@ -28,7 +28,7 @@ public class ClientRoute extends RouteBuilder { from("timer:trigger?period=500").streamCaching() .bean("counterBean") .log(" Client request: ${body}") - .hystrix() + .circuitBreaker() // see application.properties how hystrix is configured .to("http://localhost:9090/service1") //.onFallback() diff --git a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfiguration.java b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfiguration.java index 1d44fc2..aa62b27 100644 --- a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfiguration.java +++ b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfiguration.java @@ -21,6 +21,7 @@ import org.apache.camel.model.HystrixConfigurationDefinition; import org.springframework.context.annotation.Bean; public class HystrixHierarchicalConfiguration { + @Bean(name = "ref-hystrix") public HystrixConfigurationDefinition hystrixConfiguration() { return new HystrixConfigurationDefinition() @@ -35,8 +36,8 @@ public class HystrixHierarchicalConfiguration { public void configure() throws Exception { from("direct:start") .routeId("hystrix-route") - .hystrix() - .hystrixConfiguration("ref-hystrix") + .circuitBreaker() + .configuration("ref-hystrix") .hystrixConfiguration() .groupKey("local-conf-group-key") .end() diff --git a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfigurationTest.java b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfigurationTest.java index b7171e3..e3126aa 100644 --- a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfigurationTest.java +++ b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixHierarchicalConfigurationTest.java @@ -17,8 +17,8 @@ package org.apache.camel.component.hystrix.processor; import org.apache.camel.CamelContext; +import org.apache.camel.model.CircuitBreakerDefinition; import org.apache.camel.model.HystrixConfigurationDefinition; -import org.apache.camel.model.HystrixDefinition; import org.apache.camel.model.Model; import org.apache.camel.model.RouteDefinition; import org.junit.Assert; @@ -52,7 +52,7 @@ public class HystrixHierarchicalConfigurationTest { @Test public void testConfiguration() throws Exception { RouteDefinition routeDefinition = camelContext.getExtension(Model.class).getRouteDefinition("hystrix-route"); - HystrixDefinition hystrixDefinition = findHystrixDefinition(routeDefinition); + CircuitBreakerDefinition hystrixDefinition = findCircuitBreaker(routeDefinition); Assert.assertNotNull(hystrixDefinition); @@ -68,10 +68,10 @@ public class HystrixHierarchicalConfigurationTest { // Helper // ********************************************** - private HystrixDefinition findHystrixDefinition(RouteDefinition routeDefinition) throws Exception { + private CircuitBreakerDefinition findCircuitBreaker(RouteDefinition routeDefinition) throws Exception { return routeDefinition.getOutputs().stream() - .filter(HystrixDefinition.class::isInstance) - .map(HystrixDefinition.class::cast) + .filter(CircuitBreakerDefinition.class::isInstance) + .map(CircuitBreakerDefinition.class::cast) .findFirst() .orElseThrow(() -> new IllegalStateException("Unable to find a HystrixDefinition")); } diff --git a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfiguration.java b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfiguration.java index e61c48f..ffce8a9 100644 --- a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfiguration.java +++ b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfiguration.java @@ -21,6 +21,7 @@ import org.apache.camel.model.HystrixConfigurationDefinition; import org.springframework.context.annotation.Bean; public class HystrixMultiConfiguration { + @Bean(name = "bean-conf") public HystrixConfigurationDefinition hystrixBeanConfiguration() { return new HystrixConfigurationDefinition() @@ -34,16 +35,16 @@ public class HystrixMultiConfiguration { public void configure() throws Exception { from("direct:start-1") .routeId("hystrix-route-1") - .hystrix() - .hystrixConfiguration("conf-1") + .circuitBreaker() + .configuration("conf-1") .to("direct:foo") .onFallback() .transform().constant("Fallback message") .end(); from("direct:start-2") .routeId("hystrix-route-2") - .hystrix() - .hystrixConfiguration("conf-2") + .circuitBreaker() + .configuration("conf-2") .to("direct:foo") .onFallback() .transform().constant("Fallback message") diff --git a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfigurationTest.java b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfigurationTest.java index 36dd08f..9e736fd 100644 --- a/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfigurationTest.java +++ b/platforms/spring-boot/components-starter/camel-hystrix-starter/src/test/java/org/apache/camel/component/hystrix/processor/HystrixMultiConfigurationTest.java @@ -24,7 +24,6 @@ import org.apache.camel.Navigate; import org.apache.camel.Processor; import org.apache.camel.Route; import org.apache.camel.model.HystrixConfigurationDefinition; -import org.apache.camel.model.HystrixDefinition; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith;