From 3c31664ea0576676f94d08b0950f467508668911 Mon Sep 17 00:00:00 2001 From: sbalachandran Date: Sun, 7 Aug 2016 22:06:57 -0400 Subject: [PATCH 1/3] Updated with Hystrix integration to spring app --- .../java/com/baeldung/hystrix/AppConfig.java | 13 +++++++++++++ .../com/baeldung/hystrix/CommandHelloWorld.java | 0 .../com/baeldung/hystrix/HystrixAspect.java | 7 +++++++ .../baeldung/hystrix/HystrixCircuitBreaker.java | 7 +++++++ .../com/baeldung/hystrix/HystrixController.java | 17 +++++++++++++++++ .../hystrix/RemoteServiceSimulator.java | 15 --------------- .../hystrix/RemoteServiceTestCommand.java | 0 .../hystrix/RemoteServiceTestSimulator.java | 0 .../baeldung/hystrix/SpringExistingClient.java | 7 +++++++ .../src/main/resources/application.properties | 0 10 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java rename hystrix/src/{test => main}/java/com/baeldung/hystrix/CommandHelloWorld.java (100%) create mode 100644 hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java create mode 100644 hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java create mode 100644 hystrix/src/main/java/com/baeldung/hystrix/HystrixController.java delete mode 100644 hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceSimulator.java rename hystrix/src/{test => main}/java/com/baeldung/hystrix/RemoteServiceTestCommand.java (100%) rename hystrix/src/{test => main}/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java (100%) create mode 100644 hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java create mode 100644 hystrix/src/main/resources/application.properties diff --git a/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java b/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java new file mode 100644 index 0000000000..8102428e9a --- /dev/null +++ b/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java @@ -0,0 +1,13 @@ +package com.baeldung.hystrix; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; + +@SpringBootApplication +public class AppConfig { + + public static void main(String[] args) { + SpringApplication.run(AppConfig.class, args); + } +} diff --git a/hystrix/src/test/java/com/baeldung/hystrix/CommandHelloWorld.java b/hystrix/src/main/java/com/baeldung/hystrix/CommandHelloWorld.java similarity index 100% rename from hystrix/src/test/java/com/baeldung/hystrix/CommandHelloWorld.java rename to hystrix/src/main/java/com/baeldung/hystrix/CommandHelloWorld.java diff --git a/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java b/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java new file mode 100644 index 0000000000..2ea0163ab1 --- /dev/null +++ b/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java @@ -0,0 +1,7 @@ +package com.baeldung.hystrix; + +/** + * Created by sbalachandran on 8/5/2016. + */ +public class HystrixAspect { +} diff --git a/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java b/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java new file mode 100644 index 0000000000..9377d83495 --- /dev/null +++ b/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java @@ -0,0 +1,7 @@ +package com.baeldung.hystrix; + +/** + * Created by sbalachandran on 8/5/2016. + */ +public class HystrixCircuitBreaker { +} diff --git a/hystrix/src/main/java/com/baeldung/hystrix/HystrixController.java b/hystrix/src/main/java/com/baeldung/hystrix/HystrixController.java new file mode 100644 index 0000000000..a8ca0adef2 --- /dev/null +++ b/hystrix/src/main/java/com/baeldung/hystrix/HystrixController.java @@ -0,0 +1,17 @@ +package com.baeldung.hystrix; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HystrixController { + + @Autowired + private SpringExistingClient client; + + @RequestMapping("/") + public String index() throws InterruptedException{ + return client.invokeRemoteService(); + } +} diff --git a/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceSimulator.java b/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceSimulator.java deleted file mode 100644 index 3efd579d84..0000000000 --- a/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceSimulator.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.hystrix; - - -public class RemoteServiceSimulator { - - public String checkSomething(final long timeout) throws InterruptedException { - - System.out.print(String.format("Waiting %sms. ", timeout)); - - // to simulate a real world delay in processing. - Thread.sleep(timeout); - - return "Done waiting."; - } -} diff --git a/hystrix/src/test/java/com/baeldung/hystrix/RemoteServiceTestCommand.java b/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestCommand.java similarity index 100% rename from hystrix/src/test/java/com/baeldung/hystrix/RemoteServiceTestCommand.java rename to hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestCommand.java diff --git a/hystrix/src/test/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java b/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java similarity index 100% rename from hystrix/src/test/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java rename to hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java diff --git a/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java b/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java new file mode 100644 index 0000000000..b08f61a777 --- /dev/null +++ b/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java @@ -0,0 +1,7 @@ +package com.baeldung.hystrix; + +/** + * Created by sbalachandran on 8/5/2016. + */ +public class SpringExistingClient { +} diff --git a/hystrix/src/main/resources/application.properties b/hystrix/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 From bc38da4f43861225bb3e96f3d7c6df04f588138c Mon Sep 17 00:00:00 2001 From: sbalachandran Date: Sun, 7 Aug 2016 22:11:59 -0400 Subject: [PATCH 2/3] added missing new files --- hystrix/pom.xml | 35 +++++++- .../java/com/baeldung/hystrix/AppConfig.java | 9 ++- .../com/baeldung/hystrix/HystrixAspect.java | 80 ++++++++++++++++++- .../hystrix/HystrixCircuitBreaker.java | 12 ++- .../hystrix/SpringExistingClient.java | 16 +++- .../src/main/resources/application.properties | 8 ++ .../baeldung/hystrix/HystrixTimeoutTest.java | 77 ++++++++++++++++-- 7 files changed, 217 insertions(+), 20 deletions(-) diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 0ec5fa0411..381adfbcd5 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -6,9 +6,15 @@ com.baeldung hystrix 1.0 - hystrix + + org.springframework.boot + spring-boot-starter-parent + 1.4.0.RELEASE + + + @@ -32,12 +38,35 @@ + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-aop + + com.netflix.hystrix hystrix-core ${hystrix-core.version} + + com.netflix.hystrix + hystrix-metrics-event-stream + 1.3.16 + + + + + com.netflix.rxjava rxjava-core @@ -62,6 +91,10 @@ + + org.springframework.boot + spring-boot-maven-plugin + org.apache.maven.plugins maven-compiler-plugin diff --git a/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java b/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java index 8102428e9a..8b11ac99c3 100644 --- a/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java +++ b/hystrix/src/main/java/com/baeldung/hystrix/AppConfig.java @@ -1,8 +1,10 @@ package com.baeldung.hystrix; +import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ApplicationContext; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class AppConfig { @@ -10,4 +12,9 @@ public class AppConfig { public static void main(String[] args) { SpringApplication.run(AppConfig.class, args); } + + @Bean + public ServletRegistrationBean adminServletRegistrationBean() { + return new ServletRegistrationBean(new HystrixMetricsStreamServlet(), "/hystrix.stream"); + } } diff --git a/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java b/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java index 2ea0163ab1..c2e4af8edb 100644 --- a/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java +++ b/hystrix/src/main/java/com/baeldung/hystrix/HystrixAspect.java @@ -1,7 +1,81 @@ package com.baeldung.hystrix; -/** - * Created by sbalachandran on 8/5/2016. - */ +import com.netflix.hystrix.*; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +@Aspect public class HystrixAspect { + + private HystrixCommand.Setter config; + private HystrixCommandProperties.Setter commandProperties; + private HystrixThreadPoolProperties.Setter threadPoolProperties; + + @Around("@annotation(com.baeldung.hystrix.HystrixCircuitBreaker)") + public Object circuitBreakerAround(final ProceedingJoinPoint aJoinPoint) { + return new RemoteServiceCommand(config, aJoinPoint).execute(); + } + + @PostConstruct + private void setup() { + this.config = HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey)); + this.config = config.andCommandKey(HystrixCommandKey.Factory.asKey(key)); + + this.commandProperties = HystrixCommandProperties.Setter(); + this.commandProperties.withExecutionTimeoutInMilliseconds(executionTimeout); + this.commandProperties.withCircuitBreakerSleepWindowInMilliseconds(sleepWindow); + + this.threadPoolProperties= HystrixThreadPoolProperties.Setter(); + this.threadPoolProperties.withMaxQueueSize(maxThreadCount).withCoreSize(coreThreadCount).withMaxQueueSize(queueCount); + + this.config.andCommandPropertiesDefaults(commandProperties); + this.config.andThreadPoolPropertiesDefaults(threadPoolProperties); + } + + private static class RemoteServiceCommand extends HystrixCommand { + + private final ProceedingJoinPoint joinPoint; + + RemoteServiceCommand(final Setter config, final ProceedingJoinPoint joinPoint) { + super(config); + this.joinPoint = joinPoint; + } + + @Override + protected String run() throws Exception { + try { + return (String) joinPoint.proceed(); + } catch (final Throwable th) { + throw new Exception(th); + } + + } + } + + @Value("${remoteservice.command.execution.timeout}") + private int executionTimeout; + + @Value("${remoteservice.command.sleepwindow}") + private int sleepWindow; + + @Value("${remoteservice.command.threadpool.maxsize}") + private int maxThreadCount; + + @Value("${remoteservice.command.threadpool.coresize}") + private int coreThreadCount; + + @Value("${remoteservice.command.task.queue.size}") + private int queueCount; + + @Value("${remoteservice.command.group.key}") + private String groupKey; + + @Value("${remoteservice.command.key}") + private String key; } diff --git a/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java b/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java index 9377d83495..e7c0694a7b 100644 --- a/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java +++ b/hystrix/src/main/java/com/baeldung/hystrix/HystrixCircuitBreaker.java @@ -1,7 +1,11 @@ package com.baeldung.hystrix; -/** - * Created by sbalachandran on 8/5/2016. - */ -public class HystrixCircuitBreaker { +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface HystrixCircuitBreaker { } diff --git a/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java b/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java index b08f61a777..fab8e611d4 100644 --- a/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java +++ b/hystrix/src/main/java/com/baeldung/hystrix/SpringExistingClient.java @@ -1,7 +1,17 @@ package com.baeldung.hystrix; -/** - * Created by sbalachandran on 8/5/2016. - */ +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component("springClient") public class SpringExistingClient { + + @Value("${remoteservice.timeout}") + private int remoteServiceDelay; + + @HystrixCircuitBreaker + public String invokeRemoteService() throws InterruptedException{ + return new RemoteServiceTestSimulator(remoteServiceDelay).execute(); + } + } diff --git a/hystrix/src/main/resources/application.properties b/hystrix/src/main/resources/application.properties index e69de29bb2..abde975550 100644 --- a/hystrix/src/main/resources/application.properties +++ b/hystrix/src/main/resources/application.properties @@ -0,0 +1,8 @@ +remoteservice.command.group.key=RemoteServiceGroup +remoteservice.command.key=RemoteServiceKey +remoteservice.command.execution.timeout=10000 +remoteservice.command.threadpool.coresize=5 +remoteservice.command.threadpool.maxsize=10 +remoteservice.command.task.queue.size=5 +remoteservice.command.sleepwindow=5000 +remoteservice.timeout=5000 \ No newline at end of file diff --git a/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java b/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java index 773c76536f..9f067a0764 100644 --- a/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java +++ b/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java @@ -9,13 +9,15 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import java.util.concurrent.ExecutionException; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; public class HystrixTimeoutTest { - private static HystrixCommand.Setter config; - private static HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter(); + private HystrixCommand.Setter config; + private HystrixCommandProperties.Setter commandProperties ; @Rule @@ -23,6 +25,7 @@ public class HystrixTimeoutTest { @Before public void setup() { + commandProperties = HystrixCommandProperties.Setter(); config = HystrixCommand .Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroup1")); @@ -34,29 +37,87 @@ public class HystrixTimeoutTest { } @Test - public void givenTimeoutEqualTo100_andDefaultSettings_thenReturnSuccess() throws InterruptedException { + public void givenServiceTimeoutEqualTo100_andDefaultSettings_thenReturnSuccess() throws InterruptedException { assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(100)).execute(), equalTo("Success")); } @Test - public void givenTimeoutEqualTo10000_andDefaultSettings_thenExpectHystrixRuntimeException() throws InterruptedException { + public void givenServiceTimeoutEqualTo10000_andDefaultSettings_thenExpectHRE() throws InterruptedException { exception.expect(HystrixRuntimeException.class); new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(10_000)).execute(); } @Test - public void givenTimeoutEqualTo5000_andExecutionTimeoutEqualTo10000_thenReturnSuccess() throws InterruptedException { + public void givenServiceTimeoutEqualTo5000_andExecutionTimeoutEqualTo10000_thenReturnSuccess() + throws InterruptedException { commandProperties.withExecutionTimeoutInMilliseconds(10_000); config.andCommandPropertiesDefaults(commandProperties); - assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(5_000)).execute(), equalTo("Success")); + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(5_000)).execute(), + equalTo("Success")); } @Test - public void givenTimeoutEqualTo15000_andExecutionTimeoutEqualTo10000_thenExpectHystrixRuntimeException() throws InterruptedException { + public void givenServiceTimeoutEqualTo15000_andExecutionTimeoutEqualTo5000_thenExpectHRE() + throws InterruptedException { exception.expect(HystrixRuntimeException.class); - commandProperties.withExecutionTimeoutInMilliseconds(10_000); + commandProperties.withExecutionTimeoutInMilliseconds(5_000); config.andCommandPropertiesDefaults(commandProperties); new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(15_000)).execute(); } + @Test + public void givenServiceTimeoutEqual_andExecutionTimeout_andThreadPool_thenReturnSuccess() + throws InterruptedException { + commandProperties.withExecutionTimeoutInMilliseconds(10_000); + config.andCommandPropertiesDefaults(commandProperties); + config.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() + .withMaxQueueSize(10) + .withCoreSize(3) + .withQueueSizeRejectionThreshold(10)); + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(9_000)).execute(), + equalTo("Success")); + } + + @Test + public void givenCircuitBreakerSetup_thenReturnSuccess() throws InterruptedException { + + commandProperties.withExecutionTimeoutInMilliseconds(1000); + + commandProperties.withCircuitBreakerSleepWindowInMilliseconds(4000); + commandProperties.withExecutionIsolationStrategy( + HystrixCommandProperties.ExecutionIsolationStrategy.THREAD); + commandProperties.withCircuitBreakerEnabled(true); + commandProperties.withCircuitBreakerRequestVolumeThreshold(1); + + config.andCommandPropertiesDefaults(commandProperties); + + config.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() + .withMaxQueueSize(1) + .withCoreSize(1) + .withQueueSizeRejectionThreshold(1)); + + assertThat(this.invokeRemoteService(10000), equalTo(null)); + assertThat(this.invokeRemoteService(10000), equalTo(null)); + assertThat(this.invokeRemoteService(500), equalTo(null)); + Thread.sleep(5000); + + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(), + equalTo("Success")); + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(), + equalTo("Success")); + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(), + equalTo("Success")); + } + + public String invokeRemoteService(long timeout) throws InterruptedException{ + String response = null; + try{ + response = new RemoteServiceTestCommand(config, + new RemoteServiceTestSimulator(timeout)).execute(); + }catch(HystrixRuntimeException ex){ + System.out.println("ex = " + ex); + } + return response; + } + } From 640166999ac32c87fd2f919bd8f727242c771874 Mon Sep 17 00:00:00 2001 From: sbalachandran Date: Sun, 7 Aug 2016 22:24:14 -0400 Subject: [PATCH 3/3] fixed failing unit tests --- .../com/baeldung/hystrix/RemoteServiceTestSimulator.java | 2 +- .../test/java/com/baeldung/hystrix/HystrixTimeoutTest.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java b/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java index 54c626a67a..d302166ea8 100644 --- a/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java +++ b/hystrix/src/main/java/com/baeldung/hystrix/RemoteServiceTestSimulator.java @@ -1,7 +1,7 @@ package com.baeldung.hystrix; -class RemoteServiceTestSimulator { +public class RemoteServiceTestSimulator { private long wait; diff --git a/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java b/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java index 9f067a0764..c9ddd98367 100644 --- a/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java +++ b/hystrix/src/test/java/com/baeldung/hystrix/HystrixTimeoutTest.java @@ -52,7 +52,7 @@ public class HystrixTimeoutTest { throws InterruptedException { commandProperties.withExecutionTimeoutInMilliseconds(10_000); config.andCommandPropertiesDefaults(commandProperties); - assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(5_000)).execute(), + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(), equalTo("Success")); } @@ -74,7 +74,7 @@ public class HystrixTimeoutTest { .withMaxQueueSize(10) .withCoreSize(3) .withQueueSizeRejectionThreshold(10)); - assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(9_000)).execute(), + assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(), equalTo("Success")); } @@ -98,7 +98,6 @@ public class HystrixTimeoutTest { assertThat(this.invokeRemoteService(10000), equalTo(null)); assertThat(this.invokeRemoteService(10000), equalTo(null)); - assertThat(this.invokeRemoteService(500), equalTo(null)); Thread.sleep(5000); assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(),