├── sample-load-test ├── .gitignore ├── project │ ├── build.properties │ └── plugins.sbt ├── src │ └── test │ │ ├── resources │ │ ├── search.csv │ │ ├── logback.xml │ │ ├── recorder.conf │ │ └── gatling.conf │ │ └── scala │ │ └── msg │ │ ├── NoHystrixLoadTest.scala │ │ ├── HystrixCommandLoadTest.scala │ │ ├── AggregatePageLoadTest.scala │ │ └── CollapserLoadTest.scala └── build.sbt ├── service1 ├── src │ ├── main │ │ ├── resources │ │ │ ├── service1-local.properties │ │ │ ├── service1.properties │ │ │ ├── simplelogger.properties │ │ │ └── eureka-client.properties │ │ └── java │ │ │ └── service1 │ │ │ ├── service │ │ │ ├── MessageHandlerService.java │ │ │ └── MessageHandlerServiceImpl.java │ │ │ ├── app │ │ │ ├── SampleGovernatorAppRunner.java │ │ │ └── ApplicationMessageHandler.java │ │ │ ├── config │ │ │ ├── AppModule.java │ │ │ ├── CustomKaryonEurekaModule.java │ │ │ ├── KaryonAppModule.java │ │ │ └── AppRouteProvider.java │ │ │ ├── common │ │ │ ├── health │ │ │ │ └── HealthCheck.java │ │ │ └── LoggingInterceptor.java │ │ │ ├── governator │ │ │ └── SampleGovernatorApp.java │ │ │ └── domain │ │ │ ├── MessageAcknowledgement.java │ │ │ └── Message.java │ └── test │ │ └── java │ │ └── service1 │ │ └── SampleIntegrationTest.java ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradle.properties ├── build.gradle ├── gradlew.bat └── gradlew ├── aggregate ├── src │ ├── main │ │ ├── resources │ │ │ ├── aggregateapp-local.properties │ │ │ ├── logback.xml │ │ │ ├── eureka-client.properties │ │ │ └── aggregateapp.properties │ │ └── java │ │ │ └── aggregate │ │ │ ├── service │ │ │ ├── RemoteCallService.java │ │ │ └── RemoteCallServiceImpl.java │ │ │ ├── app │ │ │ ├── SampleGovernatorAppRunner.java │ │ │ ├── FallbackController.java │ │ │ ├── HelloWorldController.java │ │ │ ├── HelloWorldObservableController.java │ │ │ ├── RemoteCallSemaphoreController.java │ │ │ ├── NoHystrixController.java │ │ │ ├── RemoteCallController.java │ │ │ └── RemoteCachedController.java │ │ │ ├── commands │ │ │ ├── collapsed │ │ │ │ ├── PersonService.java │ │ │ │ ├── Person.java │ │ │ │ ├── PersonRequestCommand.java │ │ │ │ └── PersonRequestCollapser.java │ │ │ ├── simple │ │ │ │ └── HelloWorldCommand.java │ │ │ ├── fallback │ │ │ │ └── FallbackCommand.java │ │ │ ├── obs │ │ │ │ └── HelloWorldObservableCommand.java │ │ │ ├── cached │ │ │ │ └── CachedClientCommand.java │ │ │ ├── remote │ │ │ │ └── RemoteMessageClientCommand.java │ │ │ └── semaphore │ │ │ │ └── SemaphoreClientCommand.java │ │ │ ├── config │ │ │ ├── KaryonAppModule.java │ │ │ ├── AppModule.java │ │ │ ├── CustomKaryonEurekaModule.java │ │ │ └── AppRouteProvider.java │ │ │ ├── common │ │ │ ├── health │ │ │ │ └── HealthCheck.java │ │ │ └── LoggingInterceptor.java │ │ │ ├── domain │ │ │ ├── MessageAcknowledgement.java │ │ │ └── Message.java │ │ │ └── governator │ │ │ └── SamplePongAppGovernator.java │ └── test │ │ └── java │ │ └── aggregate │ │ └── commands │ │ ├── fallback │ │ └── FallbackCommandTest.java │ │ ├── simple │ │ ├── HelloWorldAsyncCommandTest.java │ │ ├── HelloWorldReactiveCommandTest.java │ │ └── HelloWorldCommandTest.java │ │ ├── collapsed │ │ └── CollapsedCommandTest.java │ │ └── obs │ │ └── HelloWorldObsCommandTest.java ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradle.properties ├── build.gradle └── gradlew ├── sample-hystrix-dashboard ├── src │ ├── main │ │ ├── resources │ │ │ ├── static │ │ │ │ ├── img │ │ │ │ │ └── cream_dust.png │ │ │ │ ├── fonts │ │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ │ └── glyphicons-halflings-regular.svg │ │ │ │ ├── css │ │ │ │ │ └── application.css │ │ │ │ ├── js │ │ │ │ │ └── app.js │ │ │ │ ├── html │ │ │ │ │ └── partialsHome.html │ │ │ │ └── index.html │ │ │ ├── application.properties │ │ │ └── bootstrap.yml │ │ └── java │ │ │ └── org │ │ │ └── bk │ │ │ └── consumer │ │ │ ├── service │ │ │ ├── HelloCommand.java │ │ │ └── HystrixWrappedPongClient.java │ │ │ ├── PingApplication.java │ │ │ ├── feign │ │ │ └── PongClient.java │ │ │ ├── domain │ │ │ ├── Message.java │ │ │ └── MessageAcknowledgement.java │ │ │ └── controller │ │ │ └── PingController.java │ └── test │ │ └── java │ │ └── org │ │ └── bk │ │ └── consumer │ │ └── ConsumerApplicationTests.java └── pom.xml ├── sample-eureka ├── src │ ├── main │ │ ├── resources │ │ │ └── application.yml │ │ ├── docker │ │ │ └── Dockerfile │ │ └── java │ │ │ └── org │ │ │ └── bk │ │ │ └── eureka │ │ │ └── EurekaApplication.java │ └── test │ │ └── java │ │ └── org │ │ └── bk │ │ └── eureka │ │ └── EurekaApplicationTests.java └── pom.xml ├── .gitignore └── README.adoc /sample-load-test/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .idea 3 | -------------------------------------------------------------------------------- /sample-load-test/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.8 2 | -------------------------------------------------------------------------------- /service1/src/main/resources/service1-local.properties: -------------------------------------------------------------------------------- 1 | eureka.validateInstanceId=false -------------------------------------------------------------------------------- /aggregate/src/main/resources/aggregateapp-local.properties: -------------------------------------------------------------------------------- 1 | eureka.validateInstanceId=false -------------------------------------------------------------------------------- /sample-load-test/src/test/resources/search.csv: -------------------------------------------------------------------------------- 1 | searchCriterion,searchComputerName 2 | Macbook,MacBook Pro 3 | eee,ASUS Eee PC 1005PE -------------------------------------------------------------------------------- /service1/src/main/resources/service1.properties: -------------------------------------------------------------------------------- 1 | reply.message=Reply Message 2 | netflix.platform.admin.resources.port=8079 3 | 4 | @next=service1-${@environment}.properties -------------------------------------------------------------------------------- /sample-load-test/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("io.gatling" % "gatling-sbt" % "2.1.7") 2 | 3 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "3.0.0") 4 | -------------------------------------------------------------------------------- /service1/src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=INFO 2 | org.slf4j.simplelogger.showdatetime=true 3 | org.slf4j.simplelogger.showthreadname=true 4 | 5 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/img/cream_dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/hystrixdemo/HEAD/sample-hystrix-dashboard/src/main/resources/static/img/cream_dust.png -------------------------------------------------------------------------------- /sample-eureka/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | --- 2 | server: 3 | port: 8761 4 | 5 | eureka: 6 | instance: 7 | hostname: localhost 8 | client: 9 | registerWithEureka: false 10 | fetchRegistry: false -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/hystrixdemo/HEAD/sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/hystrixdemo/HEAD/sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/hystrixdemo/HEAD/sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /sample-eureka/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM java:8 2 | VOLUME /tmp 3 | ADD sample-eureka-1.0.0-SNAPSHOT.jar /app.jar 4 | RUN bash -c 'touch /app.jar' 5 | EXPOSE 8761 6 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] -------------------------------------------------------------------------------- /service1/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Sep 29 20:46:02 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-all.zip 7 | -------------------------------------------------------------------------------- /aggregate/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 28 16:36:08 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | samplepong.ribbon.DeploymentContextBasedVipAddresses=sample-hystrix-dashboard 3 | samplepong.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 4 | samplepong.ribbon.ReadTimeout=5000 5 | samplepong.ribbon.MaxAutoRetries=2 6 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/service/MessageHandlerService.java: -------------------------------------------------------------------------------- 1 | package service1.service; 2 | 3 | import service1.domain.Message; 4 | import service1.domain.MessageAcknowledgement; 5 | import rx.Observable; 6 | 7 | public interface MessageHandlerService { 8 | Observable handleMessage(Message message); 9 | } 10 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/service/RemoteCallService.java: -------------------------------------------------------------------------------- 1 | package aggregate.service; 2 | 3 | import aggregate.domain.Message; 4 | import aggregate.domain.MessageAcknowledgement; 5 | import feign.RequestLine; 6 | 7 | public interface RemoteCallService { 8 | @RequestLine("POST /message") 9 | MessageAcknowledgement handleMessage(Message message); 10 | } 11 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/css/application.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 60px; 3 | } 4 | 5 | h1, h2, h3, h4, h5, h6 { 6 | font-family: Verdana, Georgia, Times, serif; 7 | } 8 | p, div { 9 | font-family: Verdana, Tahoma, Arial, sans-serif; 10 | font-size: 12px; 11 | } 12 | 13 | .longtext { 14 | word-break:break-all; 15 | } 16 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | application: 4 | name: sample-hystrix-dashboard 5 | cloud: 6 | config: 7 | enabled: false 8 | 9 | eureka: 10 | instance: 11 | nonSecurePort: ${server.port:8080} 12 | client: 13 | serviceUrl: 14 | defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ -------------------------------------------------------------------------------- /sample-load-test/build.sbt: -------------------------------------------------------------------------------- 1 | enablePlugins(GatlingPlugin) 2 | 3 | scalaVersion := "2.11.7" 4 | 5 | scalacOptions := Seq( 6 | "-encoding", "UTF-8", "-target:jvm-1.7", "-deprecation", 7 | "-feature", "-unchecked", "-language:implicitConversions", "-language:postfixOps") 8 | 9 | libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % "2.1.7" % "test" 10 | libraryDependencies += "io.gatling" % "gatling-test-framework" % "2.1.7" % "test" 11 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/app/SampleGovernatorAppRunner.java: -------------------------------------------------------------------------------- 1 | package service1.app; 2 | 3 | import service1.governator.SampleGovernatorApp; 4 | import com.netflix.governator.guice.BootstrapModule; 5 | import netflix.karyon.Karyon; 6 | 7 | public class SampleGovernatorAppRunner { 8 | 9 | public static void main(String[] args) { 10 | Karyon.forApplication(SampleGovernatorApp.class, (BootstrapModule[]) null) 11 | .startAndWaitTillShutdown(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /aggregate/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ${CONSOLE_LOG_PATTERN} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/config/AppModule.java: -------------------------------------------------------------------------------- 1 | package service1.config; 2 | 3 | import service1.service.MessageHandlerService; 4 | import service1.service.MessageHandlerServiceImpl; 5 | import com.google.inject.AbstractModule; 6 | import com.google.inject.Scopes; 7 | 8 | public class AppModule extends AbstractModule { 9 | 10 | 11 | @Override 12 | protected void configure() { 13 | bind(MessageHandlerService.class).to(MessageHandlerServiceImpl.class).in(Scopes.SINGLETON); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sample-eureka/src/main/java/org/bk/eureka/EurekaApplication.java: -------------------------------------------------------------------------------- 1 | package org.bk.eureka; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class EurekaApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(EurekaApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/SampleGovernatorAppRunner.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.governator.SamplePongAppGovernator; 4 | import com.netflix.governator.guice.BootstrapModule; 5 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; 6 | import netflix.karyon.Karyon; 7 | 8 | public class SampleGovernatorAppRunner { 9 | 10 | public static void main(String[] args) { 11 | Karyon.forApplication(SamplePongAppGovernator.class, (BootstrapModule[]) null) 12 | .startAndWaitTillShutdown(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/collapsed/PersonService.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.collapsed; 2 | 3 | 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | public class PersonService { 8 | 9 | public Person findPerson(Integer id) { 10 | return new Person(id, "name : " + id); 11 | } 12 | 13 | public List findPeople(List ids) { 14 | return ids 15 | .stream() 16 | .map(i -> new Person(i, "name : " + i)) 17 | .collect(Collectors.toList()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sample-eureka/src/test/java/org/bk/eureka/EurekaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.bk.eureka; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | import org.springframework.test.context.web.WebAppConfiguration; 8 | 9 | @RunWith(SpringJUnit4ClassRunner.class) 10 | @SpringApplicationConfiguration(classes = EurekaApplication.class) 11 | @WebAppConfiguration 12 | public class EurekaApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/service/HelloCommand.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer.service; 2 | 3 | import com.netflix.hystrix.HystrixCommand; 4 | import com.netflix.hystrix.HystrixCommandGroupKey; 5 | 6 | public class HelloCommand extends HystrixCommand { 7 | private static final String COMMAND_GROUP = "default"; 8 | private final String name; 9 | 10 | public HelloCommand(String name) { 11 | super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); 12 | this.name = name; 13 | } 14 | 15 | 16 | @Override 17 | protected String run() throws Exception { 18 | return "Hello, " + name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/config/CustomKaryonEurekaModule.java: -------------------------------------------------------------------------------- 1 | package service1.config; 2 | 3 | import com.netflix.appinfo.providers.MyDataCenterInstanceConfigProvider; 4 | import com.netflix.discovery.providers.DefaultEurekaClientConfigProvider; 5 | import netflix.karyon.eureka.KaryonEurekaModule; 6 | 7 | public class CustomKaryonEurekaModule extends KaryonEurekaModule { 8 | protected void configureEureka() { 9 | bindEurekaNamespace().toInstance("eureka."); 10 | bindEurekaInstanceConfig().toProvider(MyDataCenterInstanceConfigProvider.class); 11 | bindEurekaClientConfig().toProvider(DefaultEurekaClientConfigProvider.class); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/config/KaryonAppModule.java: -------------------------------------------------------------------------------- 1 | package aggregate.config; 2 | 3 | import aggregate.common.LoggingInterceptor; 4 | import io.netty.buffer.ByteBuf; 5 | import netflix.karyon.transport.http.KaryonHttpModule; 6 | 7 | 8 | public class KaryonAppModule extends KaryonHttpModule { 9 | 10 | public KaryonAppModule() { 11 | super("routerModule", ByteBuf.class, ByteBuf.class); 12 | } 13 | 14 | @Override 15 | protected void configureServer() { 16 | bindRouter().toProvider(new AppRouteProvider()); 17 | 18 | interceptorSupport().forUri("/*").intercept(LoggingInterceptor.class); 19 | 20 | server().port(8888); 21 | } 22 | } -------------------------------------------------------------------------------- /sample-load-test/src/test/scala/msg/NoHystrixLoadTest.scala: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import io.gatling.core.Predef._ 4 | import io.gatling.http.Predef._ 5 | import scala.concurrent.duration._ 6 | 7 | class NoHystrixLoadTest extends Simulation { 8 | 9 | val httpConf = http.baseURL("http://localhost:8888") 10 | 11 | val headers = Map("Accept" -> """application/json""") 12 | 13 | val scn = scenario("Get the Aggregated Page") 14 | .exec(http("request_1") 15 | .get("/noHystrix") 16 | .queryParam("message", "hello") 17 | .queryParam("delay_by","5000") 18 | .queryParam("throw_exception", "false")) 19 | 20 | setUp(scn.inject(rampUsers(50) over (1 seconds)).protocols(httpConf)) 21 | } 22 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/config/KaryonAppModule.java: -------------------------------------------------------------------------------- 1 | package service1.config; 2 | 3 | import service1.common.LoggingInterceptor; 4 | import io.netty.buffer.ByteBuf; 5 | import netflix.karyon.transport.http.KaryonHttpModule; 6 | 7 | 8 | public class KaryonAppModule extends KaryonHttpModule { 9 | 10 | public KaryonAppModule() { 11 | super("routerModule", ByteBuf.class, ByteBuf.class); 12 | } 13 | 14 | @Override 15 | protected void configureServer() { 16 | bindRouter().toProvider(new AppRouteProvider()); 17 | 18 | interceptorSupport().forUri("/*").intercept(LoggingInterceptor.class); 19 | 20 | server().port(8889); 21 | } 22 | } -------------------------------------------------------------------------------- /sample-load-test/src/test/scala/msg/HystrixCommandLoadTest.scala: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import io.gatling.core.Predef._ 4 | import io.gatling.http.Predef._ 5 | 6 | import scala.concurrent.duration._ 7 | 8 | class HystrixCommandLoadTest extends Simulation { 9 | 10 | val httpConf = http.baseURL("http://localhost:8888") 11 | 12 | val headers = Map("Accept" -> """application/json""") 13 | 14 | val scn = scenario("Get the Aggregated Page") 15 | .exec(http("request_1") 16 | .get("/message") 17 | .queryParam("message", "hello") 18 | .queryParam("delay_by","5000") 19 | .queryParam("throw_exception", "false")) 20 | 21 | setUp(scn.inject(rampUsers(50) over (1 seconds)).protocols(httpConf)) 22 | } 23 | -------------------------------------------------------------------------------- /sample-load-test/src/test/scala/msg/AggregatePageLoadTest.scala: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import io.gatling.core.Predef._ 4 | import io.gatling.http.Predef._ 5 | import scala.concurrent.duration._ 6 | 7 | class AggregatePageLoadTest extends Simulation { 8 | 9 | val httpConf = http.baseURL("http://localhost:8888") 10 | 11 | val headers = Map("Accept" -> """application/json""") 12 | 13 | val scn = scenario("Get the Aggregated Page") 14 | .exec(http("request_1") 15 | .get("/message") 16 | .queryParam("message", "hello") 17 | .queryParam("delay_by","1000") 18 | .queryParam("throw_exception", "false")) 19 | 20 | setUp(scn.inject(rampUsers(21) over (5 seconds)).protocols(httpConf)) 21 | } 22 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/config/AppModule.java: -------------------------------------------------------------------------------- 1 | package aggregate.config; 2 | 3 | import aggregate.service.RemoteCallService; 4 | import com.google.inject.AbstractModule; 5 | import feign.Feign; 6 | import feign.jackson.JacksonDecoder; 7 | import feign.jackson.JacksonEncoder; 8 | 9 | public class AppModule extends AbstractModule { 10 | 11 | 12 | @Override 13 | protected void configure() { 14 | RemoteCallService remoteCallService = Feign.builder() 15 | .encoder(new JacksonEncoder()) 16 | .decoder(new JacksonDecoder()) 17 | .target(RemoteCallService.class, "http://127.0.0.1:8889"); 18 | bind(RemoteCallService.class).toInstance(remoteCallService); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/common/health/HealthCheck.java: -------------------------------------------------------------------------------- 1 | 2 | package service1.common.health; 3 | 4 | import netflix.karyon.health.HealthCheckHandler; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.annotation.PostConstruct; 9 | 10 | public class HealthCheck implements HealthCheckHandler { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger(HealthCheck.class); 13 | 14 | @PostConstruct 15 | public void init() { 16 | logger.info("Health check initialized."); 17 | } 18 | 19 | @Override 20 | public int getStatus() { 21 | // TODO: Health check logic. 22 | logger.info("Health check invoked."); 23 | return 200; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/common/health/HealthCheck.java: -------------------------------------------------------------------------------- 1 | 2 | package aggregate.common.health; 3 | 4 | import netflix.karyon.health.HealthCheckHandler; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.annotation.PostConstruct; 9 | 10 | public class HealthCheck implements HealthCheckHandler { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger(HealthCheck.class); 13 | 14 | @PostConstruct 15 | public void init() { 16 | logger.info("Health check initialized."); 17 | } 18 | 19 | @Override 20 | public int getStatus() { 21 | // TODO: Health check logic. 22 | logger.info("Health check invoked."); 23 | return 200; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/collapsed/Person.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.collapsed; 2 | 3 | import com.google.common.base.Objects; 4 | 5 | public class Person { 6 | private final Integer id; 7 | private final String name; 8 | 9 | public Person(Integer id, String name) { 10 | this.id = id; 11 | this.name = name; 12 | } 13 | 14 | public Integer getId() { 15 | return id; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return Objects.toStringHelper(this) 25 | .add("id", id) 26 | .add("name", name) 27 | .toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/config/CustomKaryonEurekaModule.java: -------------------------------------------------------------------------------- 1 | package aggregate.config; 2 | 3 | import com.netflix.appinfo.providers.CloudInstanceConfigProvider; 4 | import com.netflix.appinfo.providers.MyDataCenterInstanceConfigProvider; 5 | import com.netflix.discovery.providers.DefaultEurekaClientConfigProvider; 6 | import netflix.karyon.eureka.KaryonEurekaModule; 7 | 8 | public class CustomKaryonEurekaModule extends KaryonEurekaModule { 9 | protected void configureEureka() { 10 | bindEurekaNamespace().toInstance("eureka."); 11 | bindEurekaInstanceConfig().toProvider(MyDataCenterInstanceConfigProvider.class); 12 | bindEurekaClientConfig().toProvider(DefaultEurekaClientConfigProvider.class); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /aggregate/src/test/java/aggregate/commands/fallback/FallbackCommandTest.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.fallback; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | 9 | public class FallbackCommandTest { 10 | private static final Logger logger = LoggerFactory.getLogger(FallbackCommandTest.class); 11 | 12 | @Test 13 | public void testFallback() throws Exception { 14 | logger.info("About to execute Fallback command"); 15 | FallbackCommand fallbackCommand = new FallbackCommand(); 16 | logger.info("Completed executing Fallback Command"); 17 | assertEquals("Falling back", fallbackCommand.execute()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sample-load-test/src/test/scala/msg/CollapserLoadTest.scala: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import io.gatling.core.Predef._ 4 | import io.gatling.http.Predef._ 5 | 6 | import scala.concurrent.duration._ 7 | 8 | class CollapserLoadTest extends Simulation { 9 | 10 | val httpConf = http.baseURL("http://localhost:8888") 11 | 12 | val headers = Map("Accept" -> """application/json""") 13 | 14 | val feeder = for ( i <- 1 to 30) yield Map("id" -> i) 15 | println(feeder) 16 | 17 | val scn = scenario("Get the Aggregated Page") 18 | .feed(feeder) 19 | .exec(http("collapser") 20 | .get("/sampleCollapser") 21 | .queryParam("id", "${id}") 22 | .queryParam("delay_by","10")) 23 | 24 | 25 | setUp(scn.inject(atOnceUsers(20)).protocols(httpConf)) 26 | } 27 | -------------------------------------------------------------------------------- /sample-load-test/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/simple/HelloWorldCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.simple; 2 | 3 | 4 | import com.netflix.hystrix.HystrixCommand; 5 | import com.netflix.hystrix.HystrixCommandGroupKey; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class HelloWorldCommand extends HystrixCommand { 10 | 11 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldCommand.class); 12 | 13 | private final String name; 14 | 15 | public HelloWorldCommand(String name) { 16 | super(HystrixCommandGroupKey.Factory.asKey("default")); 17 | this.name = name; 18 | } 19 | 20 | @Override 21 | protected String run() throws Exception { 22 | logger.info("HelloWorld Command Invoked"); 23 | return "Hello " + name; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/PingApplication.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.cloud.netflix.feign.EnableFeignClients; 7 | import org.springframework.cloud.netflix.hystrix.EnableHystrix; 8 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 9 | 10 | 11 | @SpringBootApplication 12 | @EnableEurekaClient 13 | @EnableFeignClients 14 | @EnableHystrix 15 | @EnableHystrixDashboard 16 | public class PingApplication { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(PingApplication.class, args); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /aggregate/src/test/java/aggregate/commands/simple/HelloWorldAsyncCommandTest.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.simple; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.concurrent.Future; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | public class HelloWorldAsyncCommandTest { 12 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldAsyncCommandTest.class); 13 | 14 | @Test 15 | public void testGreet() throws Exception { 16 | logger.info("About to execute HelloWorld command"); 17 | HelloWorldCommand helloWorldCommand = new HelloWorldCommand("World"); 18 | logger.info("Completed executing HelloWorld Command"); 19 | Future future = helloWorldCommand.queue(); 20 | assertEquals("Hello World", future.get()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /aggregate/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012 Netflix, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | org.gradle.daemon=true 17 | 18 | rxnetty_version=0.4.7 19 | jersey_version=1.18.1 20 | governator_version=1.3.3 21 | pytheas_version=1.25 22 | apache_httpclient_version=4.2.1 23 | eureka_version=1.1.151 24 | -------------------------------------------------------------------------------- /service1/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012 Netflix, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | org.gradle.daemon=true 17 | 18 | rxnetty_version=0.4.7 19 | jersey_version=1.18.1 20 | governator_version=1.3.3 21 | pytheas_version=1.25 22 | apache_httpclient_version=4.2.1 23 | eureka_version=1.1.151 24 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/feign/PongClient.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer.feign; 2 | 3 | import org.bk.consumer.domain.Message; 4 | import org.bk.consumer.domain.MessageAcknowledgement; 5 | import org.springframework.cloud.netflix.feign.FeignClient; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestMethod; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | 12 | @FeignClient("samplepong") 13 | public interface PongClient { 14 | 15 | @RequestMapping(method = RequestMethod.POST, value = "/message", 16 | produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) 17 | @ResponseBody 18 | MessageAcknowledgement sendMessage(@RequestBody Message message); 19 | } -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/fallback/FallbackCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.fallback; 2 | 3 | import com.netflix.hystrix.HystrixCommand; 4 | import com.netflix.hystrix.HystrixCommandGroupKey; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class FallbackCommand extends HystrixCommand { 9 | 10 | private static final String COMMAND_GROUP="default"; 11 | private static final Logger logger = LoggerFactory.getLogger(FallbackCommand.class); 12 | 13 | 14 | public FallbackCommand() { 15 | super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); 16 | } 17 | 18 | @Override 19 | protected String run() throws Exception { 20 | throw new RuntimeException("Always fail"); 21 | } 22 | 23 | @Override 24 | protected String getFallback() { 25 | logger.info("About to fallback"); 26 | return "Falling back"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/domain/Message.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer.domain; 2 | 3 | 4 | public class Message { 5 | private String id; 6 | private String payload; 7 | 8 | public Message() { 9 | 10 | } 11 | 12 | public Message(String id, String payload) { 13 | this.id = id; 14 | this.payload = payload; 15 | } 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public void setId(String id) { 22 | this.id = id; 23 | } 24 | 25 | public String getPayload() { 26 | return payload; 27 | } 28 | 29 | public void setPayload(String payload) { 30 | this.payload = payload; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "Message{" + 36 | "id='" + id + '\'' + 37 | ", payload='" + payload + '\'' + 38 | '}'; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/collapsed/PersonRequestCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.collapsed; 2 | 3 | import com.netflix.hystrix.HystrixCommand; 4 | import com.netflix.hystrix.HystrixCommandGroupKey; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.List; 9 | 10 | public class PersonRequestCommand extends HystrixCommand>{ 11 | 12 | private final List ids; 13 | private final PersonService personService = new PersonService(); 14 | private static final Logger logger = LoggerFactory.getLogger(PersonRequestCommand.class); 15 | 16 | public PersonRequestCommand(List ids) { 17 | super(HystrixCommandGroupKey.Factory.asKey("default")); 18 | this.ids = ids; 19 | } 20 | 21 | @Override 22 | protected List run() throws Exception { 23 | logger.info("Retrieving details for : " + this.ids); 24 | return personService.findPeople(this.ids); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /aggregate/src/test/java/aggregate/commands/simple/HelloWorldReactiveCommandTest.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.simple; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import rx.Observable; 7 | 8 | import java.util.concurrent.CountDownLatch; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | public class HelloWorldReactiveCommandTest { 13 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldReactiveCommandTest.class); 14 | 15 | @Test 16 | public void testGreet() throws Exception { 17 | logger.info("About to execute HelloWorld command"); 18 | HelloWorldCommand helloWorldCommand = new HelloWorldCommand("World"); 19 | logger.info("Completed executing HelloWorld Command"); 20 | Observable obs = helloWorldCommand.toObservable(); 21 | 22 | CountDownLatch l = new CountDownLatch(1); 23 | obs.subscribe(System.out::println, t -> l.countDown(), () -> l.countDown()); 24 | l.await(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/domain/MessageAcknowledgement.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer.domain; 2 | 3 | 4 | public class MessageAcknowledgement { 5 | 6 | private String id; 7 | private String received; 8 | private String payload; 9 | 10 | public MessageAcknowledgement() { 11 | 12 | } 13 | 14 | public MessageAcknowledgement(String id, String received, String payload) { 15 | this.id = id; 16 | this.received = received; 17 | this.payload = payload; 18 | } 19 | 20 | public String getId() { 21 | return id; 22 | } 23 | 24 | public void setId(String id) { 25 | this.id = id; 26 | } 27 | 28 | public String getPayload() { 29 | return payload; 30 | } 31 | 32 | public void setPayload(String payload) { 33 | this.payload = payload; 34 | } 35 | 36 | public String getReceived() { 37 | return received; 38 | } 39 | 40 | public void setReceived(String received) { 41 | this.received = received; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/governator/SampleGovernatorApp.java: -------------------------------------------------------------------------------- 1 | package service1.governator; 2 | 3 | import service1.config.CustomKaryonEurekaModule; 4 | import com.google.inject.Singleton; 5 | import com.netflix.governator.annotations.Modules; 6 | import netflix.adminresources.resources.KaryonWebAdminModule; 7 | import netflix.karyon.KaryonBootstrap; 8 | import netflix.karyon.ShutdownModule; 9 | import netflix.karyon.archaius.ArchaiusBootstrap; 10 | import netflix.karyon.servo.KaryonServoModule; 11 | import service1.common.health.HealthCheck; 12 | import service1.config.AppModule; 13 | import service1.config.KaryonAppModule; 14 | 15 | @ArchaiusBootstrap 16 | @KaryonBootstrap(name = "service1", healthcheck = HealthCheck.class) 17 | @Singleton 18 | @Modules(include = { 19 | ShutdownModule.class, 20 | KaryonServoModule.class, 21 | KaryonWebAdminModule.class, 22 | CustomKaryonEurekaModule.class, // Uncomment this to enable Eureka client. 23 | AppModule.class, 24 | KaryonAppModule.class 25 | }) 26 | public interface SampleGovernatorApp {} 27 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/test/java/org/bk/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer; 2 | 3 | import com.netflix.config.DynamicPropertyFactory; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.SpringApplicationConfiguration; 7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | import org.springframework.test.context.web.WebAppConfiguration; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.equalTo; 12 | 13 | @RunWith(SpringJUnit4ClassRunner.class) 14 | @SpringApplicationConfiguration(classes = PingApplication.class) 15 | @WebAppConfiguration 16 | public class ConsumerApplicationTests { 17 | 18 | 19 | @Test 20 | public void testArchaiusProperty() { 21 | assertThat(DynamicPropertyFactory.getInstance().getStringProperty("testkey", "").get(), equalTo("testvalue")); 22 | assertThat(DynamicPropertyFactory.getInstance().getStringProperty("another.key", "").get(), equalTo("anotherkeyvalue")); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/obs/HelloWorldObservableCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.obs; 2 | 3 | 4 | import com.netflix.hystrix.HystrixCommandGroupKey; 5 | import com.netflix.hystrix.HystrixObservableCommand; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import rx.Observable; 9 | 10 | public class HelloWorldObservableCommand extends HystrixObservableCommand { 11 | 12 | private String name; 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldObservableCommand.class); 15 | 16 | public HelloWorldObservableCommand(String name) { 17 | super(HystrixCommandGroupKey.Factory.asKey("default")); 18 | this.name = name; 19 | } 20 | 21 | @Override 22 | protected Observable resumeWithFallback() { 23 | return Observable.just("Returning a Fallback"); 24 | } 25 | 26 | @Override 27 | protected Observable construct() { 28 | logger.info("HelloWorldObservableCommand invoked"); 29 | return Observable.just("Hello " + this.name); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/domain/MessageAcknowledgement.java: -------------------------------------------------------------------------------- 1 | package service1.domain; 2 | 3 | 4 | import javax.xml.bind.annotation.XmlRootElement; 5 | 6 | @XmlRootElement 7 | public class MessageAcknowledgement { 8 | 9 | private String id; 10 | private String received; 11 | private String payload; 12 | 13 | public MessageAcknowledgement() { 14 | 15 | } 16 | 17 | public MessageAcknowledgement(String id, String received, String payload) { 18 | this.id = id; 19 | this.received = received; 20 | this.payload = payload; 21 | } 22 | 23 | public String getId() { 24 | return id; 25 | } 26 | 27 | public void setId(String id) { 28 | this.id = id; 29 | } 30 | 31 | public String getPayload() { 32 | return payload; 33 | } 34 | 35 | public void setPayload(String payload) { 36 | this.payload = payload; 37 | } 38 | 39 | public String getReceived() { 40 | return received; 41 | } 42 | 43 | public void setReceived(String received) { 44 | this.received = received; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/domain/MessageAcknowledgement.java: -------------------------------------------------------------------------------- 1 | package aggregate.domain; 2 | 3 | 4 | import javax.xml.bind.annotation.XmlRootElement; 5 | 6 | @XmlRootElement 7 | public class MessageAcknowledgement { 8 | 9 | private String id; 10 | private String received; 11 | private String payload; 12 | 13 | public MessageAcknowledgement() { 14 | 15 | } 16 | 17 | public MessageAcknowledgement(String id, String received, String payload) { 18 | this.id = id; 19 | this.received = received; 20 | this.payload = payload; 21 | } 22 | 23 | public String getId() { 24 | return id; 25 | } 26 | 27 | public void setId(String id) { 28 | this.id = id; 29 | } 30 | 31 | public String getPayload() { 32 | return payload; 33 | } 34 | 35 | public void setPayload(String payload) { 36 | this.payload = payload; 37 | } 38 | 39 | public String getReceived() { 40 | return received; 41 | } 42 | 43 | public void setReceived(String received) { 44 | this.received = received; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.jar 19 | *.rar 20 | *.tar 21 | *.zip 22 | 23 | # Logs and databases # 24 | ###################### 25 | *.log 26 | 27 | # OS generated files # 28 | ###################### 29 | .DS_Store* 30 | ehthumbs.db 31 | Icon? 32 | Thumbs.db 33 | 34 | # Editor Files # 35 | ################ 36 | *~ 37 | *.swp 38 | 39 | # Gradle Files # 40 | ################ 41 | .gradle 42 | .m2 43 | 44 | # Build output directies 45 | /target 46 | */target 47 | /build 48 | */build 49 | # 50 | # # IntelliJ specific files/directories 51 | 52 | # IntelliJ specific files/directories 53 | out 54 | .idea 55 | *.ipr 56 | *.iws 57 | *.iml 58 | atlassian-ide-plugin.xml 59 | 60 | # Eclipse specific files/directories 61 | .classpath 62 | .project 63 | .settings 64 | .metadata 65 | 66 | # NetBeans specific files/directories 67 | .nbattrs 68 | *.fpr 69 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/common/LoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package aggregate.common; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 5 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 6 | import netflix.karyon.transport.interceptor.DuplexInterceptor; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import rx.Observable; 10 | 11 | 12 | public class LoggingInterceptor implements DuplexInterceptor, HttpServerResponse> { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); 15 | 16 | @Override 17 | public Observable in(HttpServerRequest request, HttpServerResponse response) { 18 | logger.info("Logging interceptor invoked for direction IN."); 19 | return Observable.empty(); 20 | } 21 | 22 | @Override 23 | public Observable out(HttpServerResponse response) { 24 | logger.info("Logging interceptor invoked for direction OUT."); 25 | return Observable.empty(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/common/LoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package service1.common; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 5 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 6 | import netflix.karyon.transport.interceptor.DuplexInterceptor; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import rx.Observable; 10 | 11 | 12 | public class LoggingInterceptor implements DuplexInterceptor, HttpServerResponse> { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); 15 | 16 | @Override 17 | public Observable in(HttpServerRequest request, HttpServerResponse response) { 18 | logger.info("Logging interceptor invoked for direction IN."); 19 | return Observable.empty(); 20 | } 21 | 22 | @Override 23 | public Observable out(HttpServerResponse response) { 24 | logger.info("Logging interceptor invoked for direction OUT."); 25 | return Observable.empty(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/governator/SamplePongAppGovernator.java: -------------------------------------------------------------------------------- 1 | package aggregate.governator; 2 | 3 | import aggregate.config.CustomKaryonEurekaModule; 4 | import com.google.inject.Singleton; 5 | import com.netflix.governator.annotations.Modules; 6 | import netflix.adminresources.resources.KaryonWebAdminModule; 7 | import netflix.karyon.KaryonBootstrap; 8 | import netflix.karyon.ShutdownModule; 9 | import netflix.karyon.archaius.ArchaiusBootstrap; 10 | import netflix.karyon.eureka.KaryonEurekaModule; 11 | import netflix.karyon.servo.KaryonServoModule; 12 | import aggregate.common.health.HealthCheck; 13 | import aggregate.config.AppModule; 14 | import aggregate.config.KaryonAppModule; 15 | 16 | @ArchaiusBootstrap 17 | @KaryonBootstrap(name = "aggregateapp", healthcheck = HealthCheck.class) 18 | @Singleton 19 | @Modules(include = { 20 | // ShutdownModule.class, 21 | KaryonServoModule.class, 22 | KaryonWebAdminModule.class, 23 | CustomKaryonEurekaModule.class, // Uncomment this to enable Eureka client. 24 | AppModule.class, 25 | KaryonAppModule.class 26 | }) 27 | public interface SamplePongAppGovernator {} 28 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/controller/PingController.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer.controller; 2 | 3 | import org.bk.consumer.domain.Message; 4 | import org.bk.consumer.domain.MessageAcknowledgement; 5 | import org.bk.consumer.feign.PongClient; 6 | import org.bk.consumer.service.HelloCommand; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | public class PingController { 15 | 16 | @Autowired 17 | @Qualifier("hystrixPongClient") 18 | private PongClient pongClient; 19 | 20 | @RequestMapping("/dispatch") 21 | public MessageAcknowledgement sendMessage(@RequestBody Message message) { 22 | HelloCommand helloCommand = new HelloCommand("World"); 23 | return new MessageAcknowledgement("test", "test", helloCommand.execute()); 24 | // return this.pongClient.sendMessage(message); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/config/AppRouteProvider.java: -------------------------------------------------------------------------------- 1 | package service1.config; 2 | 3 | import service1.common.health.HealthCheck; 4 | import com.google.inject.Inject; 5 | import com.google.inject.Provider; 6 | import com.netflix.hystrix.contrib.rxnetty.metricsstream.HystrixMetricsStreamHandler; 7 | import io.netty.buffer.ByteBuf; 8 | import netflix.karyon.transport.http.SimpleUriRouter; 9 | import netflix.karyon.transport.http.health.HealthCheckEndpoint; 10 | import service1.app.ApplicationMessageHandler; 11 | 12 | public class AppRouteProvider implements Provider> { 13 | 14 | @Inject 15 | private HealthCheck healthCheck; 16 | 17 | @Inject 18 | private ApplicationMessageHandler applicationMessageHandler; 19 | 20 | @Override 21 | public SimpleUriRouter get() { 22 | SimpleUriRouter simpleUriRouter = new SimpleUriRouter(); 23 | simpleUriRouter.addUri("/healthcheck", new HealthCheckEndpoint(healthCheck)); 24 | simpleUriRouter.addUri("/message", applicationMessageHandler); 25 | simpleUriRouter.addUri("/hystrix.stream", new HystrixMetricsStreamHandler<>(simpleUriRouter)); 26 | return simpleUriRouter; 27 | } 28 | } -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/java/org/bk/consumer/service/HystrixWrappedPongClient.java: -------------------------------------------------------------------------------- 1 | package org.bk.consumer.service; 2 | 3 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 4 | import org.bk.consumer.domain.Message; 5 | import org.bk.consumer.domain.MessageAcknowledgement; 6 | import org.bk.consumer.feign.PongClient; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service("hystrixPongClient") 12 | public class HystrixWrappedPongClient implements PongClient { 13 | 14 | @Autowired 15 | @Qualifier("pongClient") 16 | private PongClient feignPongClient; 17 | 18 | @Override 19 | @HystrixCommand(groupKey = "pongGroup", fallbackMethod = "fallBackCall") 20 | public MessageAcknowledgement sendMessage(Message message) { 21 | return this.feignPongClient.sendMessage(message); 22 | } 23 | 24 | public MessageAcknowledgement fallBackCall(Message message) { 25 | MessageAcknowledgement fallback = new MessageAcknowledgement(message.getId(), message.getPayload(), "FAILED SERVICE CALL! - FALLING BACK"); 26 | return fallback; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/js/app.js: -------------------------------------------------------------------------------- 1 | var pingApp = angular.module("pingApp", ["ui.router"]); 2 | 3 | pingApp.config(function ($stateProvider, $urlRouterProvider) { 4 | $urlRouterProvider.otherwise("home"); 5 | 6 | $stateProvider 7 | .state('home', { 8 | url: '/home', 9 | templateUrl: URLS.partialsHome, 10 | controller: 'HomeController' 11 | }); 12 | }); 13 | 14 | 15 | pingApp.factory("pingFactory", function ($http) { 16 | var factory = {}; 17 | 18 | factory.getMessageResponse = function(message) { 19 | return $http.post(URLS.dispatch, {payload: message}); 20 | } 21 | 22 | return factory; 23 | }); 24 | 25 | 26 | pingApp.controller("HomeController", function ($scope, pingFactory) { 27 | 28 | function init() { 29 | $scope.message = ""; 30 | $scope.errorMessage = ""; 31 | } 32 | 33 | $scope.getMessageResponse = function(message) { 34 | pingFactory.getMessageResponse(message).success(function(data){ 35 | $scope.message = data; 36 | $scope.errorMessage = ""; 37 | }).error(function(data, status, headers, config) { 38 | $scope.errorMessage = data.error; 39 | }); 40 | } 41 | init(); 42 | }); -------------------------------------------------------------------------------- /service1/src/main/java/service1/service/MessageHandlerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package service1.service; 2 | 3 | import com.netflix.governator.annotations.Configuration; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import rx.Observable; 7 | import service1.domain.Message; 8 | import service1.domain.MessageAcknowledgement; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class MessageHandlerServiceImpl implements MessageHandlerService { 13 | private static final Logger logger = LoggerFactory.getLogger(MessageHandlerServiceImpl.class); 14 | 15 | @Configuration("reply.message") 16 | private String replyMessage; 17 | 18 | public Observable handleMessage(Message message) { 19 | logger.info("About to Acknowledge"); 20 | return Observable.timer(message.getDelayBy(), TimeUnit.MILLISECONDS) 21 | .map(l -> message.isThrowException()) 22 | .map(throwException -> { 23 | if (throwException) { 24 | throw new RuntimeException("Throwing an exception!"); 25 | } 26 | return new MessageAcknowledgement(message.getId(), message.getPayload(), replyMessage); 27 | }); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /aggregate/src/test/java/aggregate/commands/collapsed/CollapsedCommandTest.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.collapsed; 2 | 3 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; 4 | import org.junit.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import rx.Observable; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.concurrent.CountDownLatch; 12 | 13 | public class CollapsedCommandTest { 14 | private static final Logger logger = LoggerFactory.getLogger(CollapsedCommandTest.class); 15 | 16 | @Test 17 | public void testCollapse() throws Exception { 18 | HystrixRequestContext requestContext = HystrixRequestContext.initializeContext(); 19 | 20 | logger.info("About to execute Collapsed command"); 21 | List> result = new ArrayList<>(); 22 | CountDownLatch cl = new CountDownLatch(1); 23 | for (int i = 1; i <= 100; i++) { 24 | result.add(new PersonRequestCollapser(i).observe()); 25 | } 26 | 27 | Observable.merge(result).subscribe(p -> logger.info(p.toString()) 28 | , t -> logger.error(t.getMessage(), t) 29 | , () -> cl.countDown()); 30 | cl.await(); 31 | logger.info("Completed executing Collapsed Command"); 32 | requestContext.shutdown(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /service1/src/main/java/service1/domain/Message.java: -------------------------------------------------------------------------------- 1 | package service1.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class Message { 6 | 7 | private String id; 8 | private String payload; 9 | 10 | @JsonProperty("throw_exception") 11 | private boolean throwException; 12 | 13 | @JsonProperty("delay_by") 14 | private int delayBy = 0; 15 | 16 | public Message() {} 17 | 18 | public Message(String id, String payload, boolean throwException, int delayBy) { 19 | this.id = id; 20 | this.payload = payload; 21 | this.throwException = throwException; 22 | this.delayBy = delayBy; 23 | } 24 | 25 | public String getId() { 26 | return id; 27 | } 28 | 29 | public void setId(String id) { 30 | this.id = id; 31 | } 32 | 33 | public String getPayload() { 34 | return payload; 35 | } 36 | 37 | public void setPayload(String payload) { 38 | this.payload = payload; 39 | } 40 | 41 | public boolean isThrowException() { 42 | return throwException; 43 | } 44 | 45 | public void setThrowException(boolean throwException) { 46 | this.throwException = throwException; 47 | } 48 | 49 | public int getDelayBy() { 50 | return delayBy; 51 | } 52 | 53 | public void setDelayBy(int delayBy) { 54 | this.delayBy = delayBy; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /service1/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'application' 2 | apply plugin: 'idea' 3 | apply plugin: 'java' 4 | 5 | buildscript { 6 | repositories { jcenter() } 7 | dependencies { 8 | classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:2.2.0' 9 | } 10 | } 11 | 12 | repositories { 13 | jcenter() 14 | } 15 | 16 | ext { 17 | sourceCompatibility = org.gradle.api.JavaVersion.VERSION_1_8 18 | targetCompatibility = org.gradle.api.JavaVersion.VERSION_1_8 19 | } 20 | 21 | dependencies { 22 | compile 'com.netflix.karyon:karyon2-admin-web:2.7.1' 23 | compile 'com.netflix.karyon:karyon2-jersey-blocking:2.7.1' 24 | compile 'com.netflix.karyon:karyon2-eureka:2.7.1' 25 | compile 'com.netflix.karyon:karyon2-archaius:2.7.1' 26 | compile 'com.netflix.karyon:karyon2-servo:2.7.1' 27 | compile 'com.netflix.hystrix:hystrix-core:1.4.15' 28 | compile 'com.netflix.hystrix:hystrix-rx-netty-metrics-stream:1.4.15' 29 | 30 | 31 | compile 'com.google.inject:guice:3.0' 32 | compile 'org.slf4j:slf4j-api:1.7.0' 33 | testCompile 'junit:junit:4.12' 34 | runtime 'org.slf4j:slf4j-simple:1.7.0' 35 | } 36 | 37 | 38 | task runApp(dependsOn: [classes], type: JavaExec) { 39 | group = "Service1 Group" 40 | description = "Service1 App" 41 | 42 | main = "service1.app.SampleGovernatorAppRunner" 43 | classpath = sourceSets.main.runtimeClasspath 44 | 45 | systemProperty 'java.awt.headless', 'true' 46 | systemProperty 'archaius.deployment.environment', 'local' 47 | } -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/html/partialsHome.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Dispatch Ping Message

6 |
7 |
8 |
9 |
10 |
11 |
12 |

13 | 14 |

15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 | 23 |
24 |
25 | 26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /service1/src/main/resources/eureka-client.properties: -------------------------------------------------------------------------------- 1 | # Eureka Client configuration for your service. These properties are used by eureka to contact the eureka server 2 | # for all eureka operations. 3 | # Properties based configuration for eureka client. The properties specified here is mostly what the users 4 | # need to change. All of these can be specified as a java system property with -D option (eg)-Deureka.region=us-east-1 5 | # Refer to eureka wiki (https://github.com/Netflix/eureka/wiki/Configuring-Eureka) for details about these configurations. 6 | 7 | 8 | #Region where eureka is deployed -For AWS specify one of the AWS regions, for other datacenters specify a arbitrary string 9 | #indicating the region.This is normally specified as a -D option (eg) -Deureka.region=us-east-1 10 | eureka.region=default 11 | 12 | #Name of the application to be identified by other services 13 | 14 | eureka.name=service1 15 | 16 | #Virtual host name by which the clients identifies this service 17 | eureka.vipAddress=service1 18 | 19 | #The port where the service will be running and serving requests 20 | eureka.port=8889 21 | 22 | #For eureka clients running in eureka server, it needs to connect to servers in other zones 23 | eureka.preferSameZone=false 24 | 25 | #Change this if you want to use a DNS based lookup for determining other eureka servers. 26 | eureka.shouldUseDns=false 27 | 28 | eureka.default.availabilityZones=MyOwn 29 | 30 | eureka.serviceUrl.default=http://localhost:8761/eureka/ 31 | 32 | 33 | # @next=eureka-client-${@environment}.properties -------------------------------------------------------------------------------- /aggregate/src/main/resources/eureka-client.properties: -------------------------------------------------------------------------------- 1 | # Eureka Client configuration for your service. These properties are used by eureka to contact the eureka server 2 | # for all eureka operations. 3 | # Properties based configuration for eureka client. The properties specified here is mostly what the users 4 | # need to change. All of these can be specified as a java system property with -D option (eg)-Deureka.region=us-east-1 5 | # Refer to eureka wiki (https://github.com/Netflix/eureka/wiki/Configuring-Eureka) for details about these configurations. 6 | 7 | 8 | #Region where eureka is deployed -For AWS specify one of the AWS regions, for other datacenters specify a arbitrary string 9 | #indicating the region.This is normally specified as a -D option (eg) -Deureka.region=us-east-1 10 | eureka.region=default 11 | 12 | #Name of the application to be identified by other services 13 | 14 | eureka.name=aggregateapp 15 | 16 | #Virtual host name by which the clients identifies this service 17 | eureka.vipAddress=aggregateapp 18 | 19 | #The port where the service will be running and serving requests 20 | eureka.port=8888 21 | 22 | #For eureka clients running in eureka server, it needs to connect to servers in other zones 23 | eureka.preferSameZone=false 24 | 25 | #Change this if you want to use a DNS based lookup for determining other eureka servers. 26 | eureka.shouldUseDns=false 27 | 28 | eureka.default.availabilityZones=MyOwn 29 | 30 | eureka.serviceUrl.default=http://localhost:8761/eureka/ 31 | 32 | 33 | # @next=eureka-client-${@environment}.properties -------------------------------------------------------------------------------- /aggregate/src/test/java/aggregate/commands/obs/HelloWorldObsCommandTest.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.obs; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import rx.Observable; 7 | 8 | import java.util.concurrent.CountDownLatch; 9 | 10 | public class HelloWorldObsCommandTest { 11 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldObsCommandTest.class); 12 | 13 | @Test 14 | public void testHotObservable() throws Exception { 15 | logger.info("About to execute HelloWorld command"); 16 | HelloWorldObservableCommand helloWorldCommand = new HelloWorldObservableCommand("World"); 17 | logger.info("Completed executing HelloWorld Command"); 18 | Observable obs = helloWorldCommand.observe(); 19 | 20 | CountDownLatch l = new CountDownLatch(1); 21 | obs.subscribe(System.out::println, t -> l.countDown(), () -> l.countDown()); 22 | l.await(); 23 | } 24 | 25 | @Test 26 | public void testColdObservable() throws Exception { 27 | logger.info("About to execute HelloWorld command"); 28 | HelloWorldObservableCommand helloWorldCommand = new HelloWorldObservableCommand("World"); 29 | logger.info("Completed executing HelloWorld Command"); 30 | Observable obs = helloWorldCommand.toObservable(); 31 | 32 | CountDownLatch l = new CountDownLatch(1); 33 | obs.subscribe(System.out::println, t -> l.countDown(), () -> l.countDown()); 34 | l.await(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/cached/CachedClientCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.cached; 2 | 3 | import aggregate.domain.Message; 4 | import aggregate.domain.MessageAcknowledgement; 5 | import aggregate.service.RemoteCallService; 6 | import com.netflix.hystrix.HystrixCommand; 7 | import com.netflix.hystrix.HystrixCommandGroupKey; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | public class CachedClientCommand extends HystrixCommand { 12 | private static final String COMMAND_GROUP = "demo"; 13 | private static final Logger logger = LoggerFactory.getLogger(CachedClientCommand.class); 14 | 15 | private final RemoteCallService remoteCallService; 16 | private final Message message; 17 | 18 | public CachedClientCommand(RemoteCallService remoteCallService, Message message) { 19 | super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); 20 | this.remoteCallService = remoteCallService; 21 | this.message = message; 22 | } 23 | 24 | @Override 25 | protected MessageAcknowledgement run() throws Exception { 26 | logger.info("About to make Remote Call"); 27 | return this.remoteCallService.handleMessage(this.message); 28 | } 29 | 30 | @Override 31 | protected MessageAcknowledgement getFallback() { 32 | return new MessageAcknowledgement(message.getId(), message.getPayload(), "Fallback message"); 33 | } 34 | 35 | @Override 36 | protected String getCacheKey() { 37 | return this.message.hashCode() + ""; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /aggregate/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'application' 2 | apply plugin: 'idea' 3 | apply plugin: 'java' 4 | 5 | buildscript { 6 | repositories { jcenter() } 7 | dependencies { 8 | classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:2.2.0' 9 | } 10 | } 11 | 12 | repositories { 13 | jcenter() 14 | } 15 | 16 | ext { 17 | sourceCompatibility = org.gradle.api.JavaVersion.VERSION_1_8 18 | targetCompatibility = org.gradle.api.JavaVersion.VERSION_1_8 19 | } 20 | 21 | dependencies { 22 | compile 'com.netflix.karyon:karyon2-admin-web:2.7.1' 23 | compile 'com.netflix.karyon:karyon2-jersey-blocking:2.7.1' 24 | compile 'com.netflix.karyon:karyon2-eureka:2.7.1' 25 | compile 'com.netflix.karyon:karyon2-archaius:2.7.1' 26 | compile 'com.netflix.karyon:karyon2-servo:2.7.1' 27 | compile 'com.netflix.hystrix:hystrix-core:1.4.15' 28 | compile 'com.netflix.hystrix:hystrix-rx-netty-metrics-stream:1.4.15' 29 | compile 'com.netflix.feign:feign-core:8.1.2' 30 | compile 'com.netflix.feign:feign-jackson:8.1.2' 31 | 32 | 33 | compile 'com.google.inject:guice:3.0' 34 | compile 'org.slf4j:slf4j-api:1.7.0' 35 | compile 'ch.qos.logback:logback-classic:1.1.3' 36 | testCompile 'junit:junit:4.12' 37 | } 38 | 39 | 40 | task runApp(dependsOn: [classes], type: JavaExec) { 41 | group = "Aggregate-app" 42 | description = "Aggregate-app" 43 | 44 | main = "aggregate.app.SampleGovernatorAppRunner" 45 | classpath = sourceSets.main.runtimeClasspath 46 | 47 | systemProperty 'java.awt.headless', 'true' 48 | systemProperty 'archaius.deployment.environment', 'local' 49 | } -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/FallbackController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.fallback.FallbackCommand; 4 | import com.netflix.governator.annotations.AutoBindSingleton; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.handler.codec.http.HttpResponseStatus; 7 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 8 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 9 | import io.reactivex.netty.protocol.http.server.RequestHandler; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import rx.Observable; 13 | 14 | @AutoBindSingleton 15 | public class FallbackController implements RequestHandler { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(FallbackController.class); 18 | 19 | @Override 20 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 21 | return request.getContent() 22 | .flatMap(msg -> { 23 | logger.info("About to execute Fallback command"); 24 | return new FallbackCommand().observe(); 25 | }) 26 | .flatMap(str -> { 27 | try { 28 | return response.writeStringAndFlush(str); 29 | } catch (Exception e) { 30 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 31 | return response.close(); 32 | } 33 | } 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.simple.HelloWorldCommand; 4 | import com.netflix.governator.annotations.AutoBindSingleton; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.handler.codec.http.HttpResponseStatus; 7 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 8 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 9 | import io.reactivex.netty.protocol.http.server.RequestHandler; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import rx.Observable; 13 | 14 | @AutoBindSingleton 15 | public class HelloWorldController implements RequestHandler { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldController.class); 18 | 19 | @Override 20 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 21 | return request.getContent() 22 | .map(c -> request.getQueryParameters().get("greeting").get(0)) 23 | .flatMap(message -> { 24 | logger.info("About to execute HelloWorld command"); 25 | return new HelloWorldCommand(message).observe(); 26 | }) 27 | .flatMap(str -> { 28 | try { 29 | return response.writeStringAndFlush(str); 30 | } catch (Exception e) { 31 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 32 | return response.close(); 33 | } 34 | } 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /service1/src/test/java/service1/SampleIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package service1; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.handler.codec.http.HttpMethod; 6 | import io.reactivex.netty.RxNetty; 7 | import io.reactivex.netty.channel.StringTransformer; 8 | import io.reactivex.netty.protocol.http.client.HttpClient; 9 | import io.reactivex.netty.protocol.http.client.HttpClientRequest; 10 | import service1.domain.Message; 11 | import org.junit.Test; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.nio.charset.Charset; 16 | import java.util.concurrent.CountDownLatch; 17 | 18 | public class SampleIntegrationTest { 19 | 20 | private final ObjectMapper objectMapper = new ObjectMapper(); 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(SampleIntegrationTest.class); 23 | 24 | @Test 25 | public void testSampleCallToEndpoint() throws Exception { 26 | HttpClient client = RxNetty.newHttpClientBuilder("localhost", 8889).build(); 27 | HttpClientRequest request = HttpClientRequest.create(HttpMethod.POST, "/message"); 28 | 29 | String message = objectMapper.writeValueAsString(new Message("1", "Ping", false, 0)); 30 | 31 | request.withRawContent(message, StringTransformer.DEFAULT_INSTANCE); 32 | CountDownLatch l = new CountDownLatch(1); 33 | 34 | client.submit(request) 35 | .flatMap(response -> response.getContent()) 36 | .map(data -> data.toString(Charset.defaultCharset())) 37 | .subscribe(s -> { 38 | logger.info(s); 39 | l.countDown(); 40 | }); 41 | l.await(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/HelloWorldObservableController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.obs.HelloWorldObservableCommand; 4 | import aggregate.commands.simple.HelloWorldCommand; 5 | import com.netflix.governator.annotations.AutoBindSingleton; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.handler.codec.http.HttpResponseStatus; 8 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 9 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 10 | import io.reactivex.netty.protocol.http.server.RequestHandler; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import rx.Observable; 14 | 15 | @AutoBindSingleton 16 | public class HelloWorldObservableController implements RequestHandler { 17 | 18 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldObservableController.class); 19 | 20 | @Override 21 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 22 | return request.getContent() 23 | .map(c -> request.getQueryParameters().get("greeting").get(0)) 24 | .flatMap(message -> { 25 | logger.info("About to execute HelloWorld command"); 26 | return new HelloWorldObservableCommand(message).observe(); 27 | }) 28 | .flatMap(str -> { 29 | try { 30 | return response.writeStringAndFlush(str); 31 | } catch (Exception e) { 32 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 33 | return response.close(); 34 | } 35 | } 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/remote/RemoteMessageClientCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.remote; 2 | 3 | import aggregate.domain.Message; 4 | import aggregate.domain.MessageAcknowledgement; 5 | import aggregate.service.RemoteCallService; 6 | import com.netflix.hystrix.HystrixCommand; 7 | import com.netflix.hystrix.HystrixCommandGroupKey; 8 | import com.netflix.hystrix.HystrixCommandKey; 9 | import com.netflix.hystrix.HystrixCommandProperties; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | public class RemoteMessageClientCommand extends HystrixCommand { 14 | private static final String COMMAND_GROUP = "demo"; 15 | private static final Logger logger = LoggerFactory.getLogger(RemoteMessageClientCommand.class); 16 | 17 | private final RemoteCallService remoteCallService; 18 | private final Message message; 19 | 20 | public RemoteMessageClientCommand(RemoteCallService remoteCallService, Message message) { 21 | super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)); 22 | // super(Setter 23 | // .withGroupKey(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)) 24 | // .andCommandPropertiesDefaults( 25 | // HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(5000))); 26 | this.remoteCallService = remoteCallService; 27 | this.message = message; 28 | } 29 | 30 | @Override 31 | protected MessageAcknowledgement run() throws Exception { 32 | logger.info("About to make Remote Call"); 33 | return this.remoteCallService.handleMessage(this.message); 34 | } 35 | 36 | @Override 37 | protected MessageAcknowledgement getFallback() { 38 | return new MessageAcknowledgement(message.getId(), message.getPayload(), "Fallback message"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/collapsed/PersonRequestCollapser.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.collapsed; 2 | 3 | import com.netflix.hystrix.HystrixCollapser; 4 | import com.netflix.hystrix.HystrixCollapserKey; 5 | import com.netflix.hystrix.HystrixCollapserProperties; 6 | import com.netflix.hystrix.HystrixCommand; 7 | 8 | import java.util.Collection; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | import java.util.stream.Collectors; 13 | 14 | public class PersonRequestCollapser extends HystrixCollapser, Person, Integer> { 15 | 16 | private final Integer id; 17 | public PersonRequestCollapser(Integer id) { 18 | super(Setter. 19 | withCollapserKey(HystrixCollapserKey.Factory.asKey("personRequestCollapser")) 20 | .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(2000))); 21 | this.id = id; 22 | } 23 | 24 | @Override 25 | public Integer getRequestArgument() { 26 | return this.id; 27 | } 28 | 29 | @Override 30 | protected HystrixCommand> createCommand(Collection> collapsedRequests) { 31 | List ids = collapsedRequests.stream().map(cr -> cr.getArgument()).collect(Collectors.toList()); 32 | return new PersonRequestCommand(ids); 33 | } 34 | 35 | @Override 36 | protected void mapResponseToRequests(List batchResponse, Collection> collapsedRequests) { 37 | Map personMap = batchResponse.stream().collect(Collectors.toMap(Person::getId, Function.identity())); 38 | 39 | for (CollapsedRequest cr: collapsedRequests) { 40 | cr.setResponse(personMap.get(cr.getArgument())); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/commands/semaphore/SemaphoreClientCommand.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.semaphore; 2 | 3 | import aggregate.domain.Message; 4 | import aggregate.domain.MessageAcknowledgement; 5 | import aggregate.service.RemoteCallService; 6 | import com.netflix.hystrix.HystrixCommand; 7 | import com.netflix.hystrix.HystrixCommandGroupKey; 8 | import com.netflix.hystrix.HystrixCommandProperties; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public class SemaphoreClientCommand extends HystrixCommand { 13 | private static final String COMMAND_GROUP = "demo"; 14 | private static final Logger logger = LoggerFactory.getLogger(SemaphoreClientCommand.class); 15 | 16 | private final RemoteCallService remoteCallService; 17 | private final Message message; 18 | 19 | public SemaphoreClientCommand(RemoteCallService remoteCallService, Message message) { 20 | super(Setter 21 | .withGroupKey(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP)) 22 | .andCommandPropertiesDefaults( 23 | HystrixCommandProperties.Setter() 24 | .withExecutionTimeoutInMilliseconds(5000) 25 | .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))); 26 | this.remoteCallService = remoteCallService; 27 | this.message = message; 28 | } 29 | 30 | @Override 31 | protected MessageAcknowledgement run() throws Exception { 32 | logger.info("About to make Remote Call"); 33 | return this.remoteCallService.handleMessage(this.message); 34 | } 35 | 36 | @Override 37 | protected MessageAcknowledgement getFallback() { 38 | return new MessageAcknowledgement(message.getId(), message.getPayload(), "Fallback message"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/domain/Message.java: -------------------------------------------------------------------------------- 1 | package aggregate.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.google.common.base.Objects; 5 | 6 | public class Message { 7 | 8 | private String id; 9 | private String payload; 10 | 11 | @JsonProperty("throw_exception") 12 | private boolean throwException; 13 | 14 | @JsonProperty("delay_by") 15 | private int delayBy = 0; 16 | 17 | public Message() {} 18 | 19 | public Message(String id, String payload, boolean throwException, int delayBy) { 20 | this.id = id; 21 | this.payload = payload; 22 | this.throwException = throwException; 23 | this.delayBy = delayBy; 24 | } 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public void setId(String id) { 31 | this.id = id; 32 | } 33 | 34 | public String getPayload() { 35 | return payload; 36 | } 37 | 38 | public void setPayload(String payload) { 39 | this.payload = payload; 40 | } 41 | 42 | public boolean isThrowException() { 43 | return throwException; 44 | } 45 | 46 | public void setThrowException(boolean throwException) { 47 | this.throwException = throwException; 48 | } 49 | 50 | public int getDelayBy() { 51 | return delayBy; 52 | } 53 | 54 | public void setDelayBy(int delayBy) { 55 | this.delayBy = delayBy; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object o) { 60 | if (this == o) return true; 61 | if (o == null || getClass() != o.getClass()) return false; 62 | Message message = (Message) o; 63 | return Objects.equal(id, message.id) && 64 | Objects.equal(payload, message.payload); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hashCode(id, payload); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /aggregate/src/test/java/aggregate/commands/simple/HelloWorldCommandTest.java: -------------------------------------------------------------------------------- 1 | package aggregate.commands.simple; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import rx.Observable; 7 | 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.Future; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | public class HelloWorldCommandTest { 15 | private static final Logger logger = LoggerFactory.getLogger(HelloWorldCommandTest.class); 16 | 17 | @Test 18 | public void testGreetSync() throws Exception { 19 | logger.info("About to execute HelloWorld command"); 20 | HelloWorldCommand helloWorldCommand = new HelloWorldCommand("World"); 21 | assertEquals("Hello World", helloWorldCommand.execute()); 22 | logger.info("Completed executing HelloWorld Command"); 23 | } 24 | 25 | @Test 26 | public void testGreetFuture() throws Exception { 27 | logger.info("About to execute HelloWorld command"); 28 | HelloWorldCommand helloWorldCommand = new HelloWorldCommand("World"); 29 | Future future = helloWorldCommand.queue(); 30 | assertEquals("Hello World", future.get()); 31 | logger.info("Completed executing HelloWorld Command"); 32 | } 33 | 34 | @Test 35 | public void testGreetReactive() throws Exception { 36 | logger.info("About to execute HelloWorld command"); 37 | HelloWorldCommand helloWorldCommand = new HelloWorldCommand("World"); 38 | 39 | CountDownLatch l = new CountDownLatch(1); 40 | 41 | Observable obs = helloWorldCommand.observe(); 42 | obs.subscribe( 43 | s -> logger.info("Received : " + s), 44 | t -> logger.error(t.getMessage(), t), 45 | () -> l.countDown() 46 | ); 47 | l.await(5, TimeUnit.SECONDS); 48 | logger.info("Completed executing HelloWorld Command"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample Spring-cloud app 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 41 |
42 |
43 |
44 |
45 |
46 | 55 | 56 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | Hystrix Samples 2 | --------------- 3 | 4 | Start the applications in the following order: 5 | 6 | * Run Eureka - not technically required, but avoids other applications from 7 | throwing errors on the console on not finding Eureka, the endpoint is at http://localhost:8761 8 | 9 | cd sample-eureka 10 | mvn spring-boot:run 11 | 12 | * Start Hystrix Dashboard Application. This will be used for displaying the Hystrix command metrics, the endpoint is available at http://localhost:8080 13 | 14 | cd sample-hystrix-dashboard 15 | mvn spring-boot:run 16 | 17 | 18 | * Start sample service, the endpoints is available at http://localhost:8889 19 | 20 | cd service1 21 | ./gradlew runApp 22 | 23 | * Start client application, the endpoint is available at http://localhost:8888 24 | 25 | cd aggregate 26 | ./gradlew runApp 27 | 28 | Endpoints 29 | --------- 30 | 31 | The following endpoints should be available demonstrating different Hystrix features, look at the Hystrix Dashboard at http://localhost:8080/hystrix.dashboard and use the Hystrix stream available at http://localhost:8888/hystrix.stream 32 | 33 | . http://localhost:8888/hello?greeting=World - 34 | Simple Hello World Hystrix Command 35 | 36 | . http://localhost:8888/helloObservable?greeting=World - Hello World Command using `HystrixObservableCommand`. 37 | 38 | . http://localhost:8888/fallback - Sample Fallback Example 39 | 40 | . http://localhost:8888/message?message=Hello&delay_by=0&throw_exception=false - Endpoint which makes a remote request behind a Hystrix command, play around with `delay_by` and `throw_exception` parameters. 41 | 42 | . http://localhost:8888/messageSemaphore?message=Hello&delay_by=0&throw_exception=false - Endpoint which makes a remote request behind a Hystrix command but using Semaphore based isolation strategy, play around with `delay_by` and `throw_exception` parameters. 43 | 44 | . http://localhost:8888/messageCached?message=Hello&delay_by=500&throw_exception=false - Hystrix Command with Caching 45 | 46 | . http://localhost:8888/sampleCollapser?id=1 - Hystrix Request Collapsing 47 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/config/AppRouteProvider.java: -------------------------------------------------------------------------------- 1 | package aggregate.config; 2 | 3 | import aggregate.app.*; 4 | import aggregate.common.health.HealthCheck; 5 | import com.google.inject.Inject; 6 | import com.google.inject.Provider; 7 | import com.netflix.hystrix.contrib.rxnetty.metricsstream.HystrixMetricsStreamHandler; 8 | import io.netty.buffer.ByteBuf; 9 | import netflix.karyon.transport.http.SimpleUriRouter; 10 | import netflix.karyon.transport.http.health.HealthCheckEndpoint; 11 | 12 | public class AppRouteProvider implements Provider> { 13 | 14 | @Inject 15 | private HealthCheck healthCheck; 16 | 17 | @Inject 18 | private HelloWorldController helloWorldController; 19 | 20 | @Inject 21 | private HelloWorldObservableController helloWorldObservableController; 22 | 23 | 24 | @Inject 25 | private RemoteCallController remoteCallController; 26 | 27 | @Inject 28 | private RemoteCallSemaphoreController remoteCallSemaphoreController; 29 | 30 | @Inject 31 | private RemoteCachedController remoteCachedController; 32 | 33 | @Inject 34 | private FallbackController fallbackController; 35 | 36 | @Inject 37 | private NoHystrixController noHystrixController; 38 | 39 | @Override 40 | public SimpleUriRouter get() { 41 | SimpleUriRouter simpleUriRouter = new SimpleUriRouter(); 42 | simpleUriRouter.addUri("/healthcheck", new HealthCheckEndpoint(healthCheck)); 43 | simpleUriRouter.addUri("/message", remoteCallController); 44 | simpleUriRouter.addUri("/messageSemaphore", remoteCallSemaphoreController); 45 | simpleUriRouter.addUri("/messageCached", remoteCachedController); 46 | simpleUriRouter.addUri("/hystrix.stream", new HystrixMetricsStreamHandler<>(simpleUriRouter)); 47 | simpleUriRouter.addUri("/hello", helloWorldController); 48 | simpleUriRouter.addUri("/helloObservable", helloWorldObservableController); 49 | simpleUriRouter.addUri("/noHystrix", noHystrixController); 50 | simpleUriRouter.addUri("/fallback", fallbackController); 51 | return simpleUriRouter; 52 | } 53 | } -------------------------------------------------------------------------------- /aggregate/src/main/resources/aggregateapp.properties: -------------------------------------------------------------------------------- 1 | netflix.platform.admin.resources.port=8078 2 | 3 | hystrix.command.default.metrics.rollingStats.timeInMilliseconds=10000 4 | hystrix.command.default.execution.isolation.strategy=THREAD 5 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000 6 | hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=10 7 | hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 8 | hystrix.command.default.circuitBreaker.requestVolumeThreshold=20 9 | hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000 10 | 11 | hystrix.command.RemoteMessageClientCommand.metrics.rollingStats.timeInMilliseconds=10000 12 | hystrix.command.RemoteMessageClientCommand.execution.isolation.strategy=THREAD 13 | hystrix.command.RemoteMessageClientCommand.execution.isolation.thread.timeoutInMilliseconds=1000 14 | hystrix.command.RemoteMessageClientCommand.circuitBreaker.errorThresholdPercentage=50 15 | hystrix.command.RemoteMessageClientCommand.circuitBreaker.requestVolumeThreshold=20 16 | hystrix.command.RemoteMessageClientCommand.circuitBreaker.sleepWindowInMilliseconds=5000 17 | 18 | 19 | hystrix.command.HelloWorldCommand.execution.isolation.strategy=THREAD 20 | hystrix.command.HelloWorldCommand.execution.isolation.thread.timeoutInMilliseconds=1000 21 | 22 | hystrix.command.HelloWorldCommand.metrics.rollingStats.timeInMilliseconds=10000 23 | hystrix.command.HelloWorldCommand.circuitBreaker.errorThresholdPercentage=50 24 | hystrix.command.HelloWorldCommand.circuitBreaker.requestVolumeThreshold=20 25 | hystrix.command.HelloWorldCommand.circuitBreaker.sleepWindowInMilliseconds=5000 26 | 27 | 28 | hystrix.command.SempaphoreClientCommand.metrics.rollingStats.timeInMilliseconds=10000 29 | hystrix.command.SempaphoreClientCommand.execution.isolation.strategy=SEMAPHORE 30 | hystrix.command.SempaphoreClientCommand.execution.isolation.semaphore.maxConcurrentRequests=10 31 | 32 | 33 | hystrix.threadpool.demo.coreSize=10 34 | hystrix.threadpool.demo.queueSizeRejectionThreshold=5 35 | 36 | hystrix.threadpool.default.coreSize=10 37 | hystrix.threadpool.default.queueSizeRejectionThreshold=5 38 | 39 | @next=aggregateapp-${@environment}.properties -------------------------------------------------------------------------------- /service1/src/main/java/service1/app/ApplicationMessageHandler.java: -------------------------------------------------------------------------------- 1 | package service1.app; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.google.inject.Inject; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.handler.codec.http.HttpResponseStatus; 7 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 8 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 9 | import io.reactivex.netty.protocol.http.server.RequestHandler; 10 | import rx.Observable; 11 | import service1.domain.Message; 12 | import service1.service.MessageHandlerService; 13 | 14 | import java.io.IOException; 15 | import java.nio.charset.Charset; 16 | 17 | 18 | public class ApplicationMessageHandler implements RequestHandler { 19 | 20 | private final ObjectMapper objectMapper = new ObjectMapper(); 21 | 22 | private final MessageHandlerService messageHandlerService; 23 | 24 | @Inject 25 | public ApplicationMessageHandler(MessageHandlerService messageHandlerService) { 26 | this.messageHandlerService = messageHandlerService; 27 | } 28 | 29 | @Override 30 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 31 | return request.getContent().map(byteBuf -> byteBuf.toString(Charset.forName("UTF-8"))) 32 | .map(s -> { 33 | try { 34 | Message m = objectMapper.readValue(s, Message.class); 35 | return m; 36 | } catch (IOException e) { 37 | throw new RuntimeException(e); 38 | } 39 | }) 40 | .flatMap(messageHandlerService::handleMessage) 41 | .flatMap(ack -> { 42 | try { 43 | return response.writeStringAndFlush(objectMapper.writeValueAsString(ack)); 44 | } catch (Exception e) { 45 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 46 | return response.close(); 47 | } 48 | } 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/service/RemoteCallServiceImpl.java: -------------------------------------------------------------------------------- 1 | //package aggregate.service; 2 | // 3 | //import aggregate.domain.Message; 4 | //import aggregate.domain.MessageAcknowledgement; 5 | //import com.fasterxml.jackson.core.JsonProcessingException; 6 | //import com.fasterxml.jackson.databind.ObjectMapper; 7 | //import io.netty.buffer.ByteBuf; 8 | //import io.netty.handler.codec.http.HttpMethod; 9 | //import io.reactivex.netty.RxNetty; 10 | //import io.reactivex.netty.channel.StringTransformer; 11 | //import io.reactivex.netty.protocol.http.client.HttpClient; 12 | //import io.reactivex.netty.protocol.http.client.HttpClientRequest; 13 | //import org.slf4j.Logger; 14 | //import org.slf4j.LoggerFactory; 15 | //import rx.Observable; 16 | // 17 | //import java.nio.charset.Charset; 18 | // 19 | //public class RemoteCallServiceImpl implements RemoteCallService { 20 | // private static final Logger logger = LoggerFactory.getLogger(RemoteCallServiceImpl.class); 21 | // private final HttpClient httpClient; 22 | // private final ObjectMapper objectMapper = new ObjectMapper(); 23 | // 24 | // public RemoteCallServiceImpl() { 25 | // this.httpClient = RxNetty.newHttpClientBuilder("localhost", 8889).build(); 26 | // } 27 | // 28 | // public Observable handleMessage(Message message) { 29 | // logger.info("About to call Remote service"); 30 | // 31 | // HttpClientRequest request = HttpClientRequest.create(HttpMethod.POST, "/message"); 32 | // 33 | // try { 34 | // String messageAsString = this.objectMapper.writeValueAsString(message); 35 | // 36 | // request.withRawContent(messageAsString, StringTransformer.DEFAULT_INSTANCE); 37 | // 38 | // return this.httpClient.submit(request) 39 | // .flatMap(response -> response.getContent()) 40 | // .map(data -> data.toString(Charset.defaultCharset())) 41 | // .map(data -> { 42 | // try { 43 | // return this.objectMapper.readValue(data, MessageAcknowledgement.class); 44 | // }catch (Exception e) { 45 | // throw new RuntimeException(e); 46 | // } 47 | // }); 48 | // } catch (JsonProcessingException e) { 49 | // e.printStackTrace(); 50 | // return Observable.error(e); 51 | // } 52 | // 53 | // } 54 | // 55 | //} 56 | -------------------------------------------------------------------------------- /sample-load-test/src/test/resources/recorder.conf: -------------------------------------------------------------------------------- 1 | recorder { 2 | core { 3 | #encoding = "utf-8" # The encoding used for reading/writing request bodies and the generated simulation 4 | #outputFolder = "" # The folder where generated simulation will we written 5 | #package = "" # The package's name of the generated simulation 6 | #className = "RecordedSimulation" # The name of the generated Simulation class 7 | #thresholdForPauseCreation = 100 # The minimum time, in milliseconds, that must pass between requests to trigger a pause creation 8 | #saveConfig = false # When set to true, the configuration from the Recorder GUI overwrites this configuration 9 | } 10 | filters { 11 | #filterStrategy = "Disabled" # The selected filter resources filter strategy (currently supported : "Disabled", "BlackList", "WhiteList") 12 | #whitelist = [] # The list of ressources patterns that are part of the Recorder's whitelist 13 | #blacklist = [] # The list of ressources patterns that are part of the Recorder's blacklist 14 | } 15 | http { 16 | #automaticReferer = true # When set to false, write the referer + enable 'disableAutoReferer' in the generated simulation 17 | #followRedirect = true # When set to false, write redirect requests + enable 'disableFollowRedirect' in the generated simulation 18 | #removeConditionalCache = true # When set to true, removes from the generated requests headers leading to request caching 19 | #inferHtmlResources = true # When set to true, add inferred resources + set 'inferHtmlResources' with the configured blacklist/whitelist in the generated simulation 20 | } 21 | proxy { 22 | #port = 8000 # Local port used by Gatling's Proxy for HTTP/HTTPS 23 | outgoing { 24 | #host = "" # The outgoing proxy's hostname 25 | #username = "" # The username to use to connect to the outgoing proxy 26 | #password = "" # The password corresponding to the user to use to connect to the outgoing proxy 27 | #port = 0 # The HTTP port to use to connect to the outgoing proxy 28 | #sslPort = 0 # If set, The HTTPS port to use to connect to the outgoing proxy 29 | } 30 | } 31 | netty { 32 | #maxInitialLineLength = 10000 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") 33 | #maxHeaderSize = 20000 # Maximum size, in bytes, of each request's headers 34 | #maxChunkSize = 8192 # Maximum length of the content or each chunk 35 | #maxContentLength = 100000000 # Maximum length of the aggregated content of each response 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/RemoteCallSemaphoreController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.semaphore.SemaphoreClientCommand; 4 | import aggregate.domain.Message; 5 | import aggregate.service.RemoteCallService; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.google.inject.Inject; 8 | import com.netflix.governator.annotations.AutoBindSingleton; 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.handler.codec.http.HttpResponseStatus; 11 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 12 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 13 | import io.reactivex.netty.protocol.http.server.RequestHandler; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import rx.Observable; 17 | 18 | 19 | @AutoBindSingleton 20 | public class RemoteCallSemaphoreController implements RequestHandler { 21 | 22 | private final ObjectMapper objectMapper = new ObjectMapper(); 23 | 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(RemoteCallSemaphoreController.class); 26 | 27 | private final RemoteCallService remoteCallService; 28 | 29 | @Inject 30 | public RemoteCallSemaphoreController(RemoteCallService remoteCallService) { 31 | this.remoteCallService = remoteCallService; 32 | } 33 | 34 | @Override 35 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 36 | return request.getContent() 37 | .map(s -> { 38 | boolean throwException = Boolean.valueOf(request.getQueryParameters().get("throw_exception").get(0)); 39 | int delayBy = Integer.valueOf(request.getQueryParameters().get("delay_by").get(0)); 40 | String msg = request.getQueryParameters().get("message").get(0); 41 | Message message = new Message("id", msg, throwException, delayBy); 42 | return message; 43 | }) 44 | .flatMap(message -> { 45 | logger.info("About to make remote call"); 46 | return new SemaphoreClientCommand(this.remoteCallService, message).observe(); 47 | }) 48 | .flatMap(ack -> { 49 | try { 50 | return response.writeStringAndFlush(objectMapper.writeValueAsString(ack)); 51 | } catch (Exception e) { 52 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 53 | return response.close(); 54 | } 55 | } 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/NoHystrixController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.remote.RemoteMessageClientCommand; 4 | import aggregate.domain.Message; 5 | import aggregate.service.RemoteCallService; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.google.inject.Inject; 8 | import com.netflix.governator.annotations.AutoBindSingleton; 9 | import feign.Feign; 10 | import feign.jackson.JacksonDecoder; 11 | import feign.jackson.JacksonEncoder; 12 | import io.netty.buffer.ByteBuf; 13 | import io.netty.handler.codec.http.HttpResponseStatus; 14 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 15 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 16 | import io.reactivex.netty.protocol.http.server.RequestHandler; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import rx.Observable; 20 | 21 | 22 | @AutoBindSingleton 23 | public class NoHystrixController implements RequestHandler { 24 | 25 | private final ObjectMapper objectMapper = new ObjectMapper(); 26 | 27 | private static final Logger logger = LoggerFactory.getLogger(RemoteCallController.class); 28 | 29 | private final RemoteCallService remoteCallService; 30 | 31 | @Inject 32 | public NoHystrixController(RemoteCallService remoteCallService) { 33 | this.remoteCallService = remoteCallService; 34 | } 35 | 36 | @Override 37 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 38 | return request.getContent() 39 | .map(s -> { 40 | boolean throwException = Boolean.valueOf(request.getQueryParameters().get("throw_exception").get(0)); 41 | int delayBy = Integer.valueOf(request.getQueryParameters().get("delay_by").get(0)); 42 | String msg = request.getQueryParameters().get("message").get(0); 43 | Message message = new Message("id", msg, throwException, delayBy); 44 | return message; 45 | }) 46 | .map(message -> { 47 | logger.info("About to make remote call"); 48 | return remoteCallService.handleMessage(message); 49 | }) 50 | .flatMap(ack -> { 51 | try { 52 | return response.writeStringAndFlush(objectMapper.writeValueAsString(ack)); 53 | } catch (Exception e) { 54 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 55 | return response.close(); 56 | } 57 | } 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /service1/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/RemoteCallController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.remote.RemoteMessageClientCommand; 4 | import aggregate.domain.Message; 5 | import aggregate.service.RemoteCallService; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.google.inject.Inject; 8 | import com.netflix.governator.annotations.AutoBindSingleton; 9 | import feign.Feign; 10 | import feign.jackson.JacksonDecoder; 11 | import feign.jackson.JacksonEncoder; 12 | import io.netty.buffer.ByteBuf; 13 | import io.netty.handler.codec.http.HttpResponseStatus; 14 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 15 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 16 | import io.reactivex.netty.protocol.http.server.RequestHandler; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import rx.Observable; 20 | 21 | 22 | @AutoBindSingleton 23 | public class RemoteCallController implements RequestHandler { 24 | 25 | private final ObjectMapper objectMapper = new ObjectMapper(); 26 | 27 | // private final RemoteCallService remoteCallService; 28 | 29 | private static final Logger logger = LoggerFactory.getLogger(RemoteCallController.class); 30 | 31 | private final RemoteCallService remoteCallService; 32 | 33 | @Inject 34 | public RemoteCallController(RemoteCallService remoteCallService) { 35 | this.remoteCallService = remoteCallService; 36 | } 37 | 38 | @Override 39 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 40 | return request.getContent() 41 | .map(s -> { 42 | boolean throwException = Boolean.valueOf(request.getQueryParameters().get("throw_exception").get(0)); 43 | int delayBy = Integer.valueOf(request.getQueryParameters().get("delay_by").get(0)); 44 | String msg = request.getQueryParameters().get("message").get(0); 45 | Message message = new Message("id", msg, throwException, delayBy); 46 | return message; 47 | }) 48 | .flatMap(message -> { 49 | logger.info("About to make remote call"); 50 | return new RemoteMessageClientCommand(this.remoteCallService, message).observe(); 51 | }) 52 | .flatMap(ack -> { 53 | try { 54 | return response.writeStringAndFlush(objectMapper.writeValueAsString(ack)); 55 | } catch (Exception e) { 56 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 57 | return response.close(); 58 | } 59 | } 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sample-eureka/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.bk 7 | sample-eureka 8 | 1.0.0-SNAPSHOT 9 | jar 10 | 11 | sample-eureka 12 | Eureka Sample App 13 | 14 | 15 | org.springframework.cloud 16 | spring-cloud-starter-parent 17 | Brixton.M1 18 | 19 | 20 | 21 | org.bk.eureka.EurekaApplication 22 | 23 | 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-eureka-server 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-actuator 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | 55 | 56 | 57 | spring-milestones 58 | Spring Milestones 59 | http://repo.spring.io/milestone 60 | 61 | false 62 | 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | http://repo.spring.io/milestone 70 | 71 | false 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /aggregate/src/main/java/aggregate/app/RemoteCachedController.java: -------------------------------------------------------------------------------- 1 | package aggregate.app; 2 | 3 | import aggregate.commands.cached.CachedClientCommand; 4 | import aggregate.domain.Message; 5 | import aggregate.domain.MessageAcknowledgement; 6 | import aggregate.service.RemoteCallService; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import com.google.inject.Inject; 9 | import com.netflix.governator.annotations.AutoBindSingleton; 10 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; 11 | import io.netty.buffer.ByteBuf; 12 | import io.netty.handler.codec.http.HttpResponseStatus; 13 | import io.reactivex.netty.protocol.http.server.HttpServerRequest; 14 | import io.reactivex.netty.protocol.http.server.HttpServerResponse; 15 | import io.reactivex.netty.protocol.http.server.RequestHandler; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | import rx.Observable; 19 | 20 | 21 | @AutoBindSingleton 22 | public class RemoteCachedController implements RequestHandler { 23 | 24 | private final ObjectMapper objectMapper = new ObjectMapper(); 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(RemoteCachedController.class); 27 | 28 | private final RemoteCallService remoteCallService; 29 | 30 | @Inject 31 | public RemoteCachedController(RemoteCallService remoteCallService) { 32 | this.remoteCallService = remoteCallService; 33 | } 34 | 35 | @Override 36 | public Observable handle(HttpServerRequest request, HttpServerResponse response) { 37 | final HystrixRequestContext context = HystrixRequestContext.initializeContext(); 38 | 39 | return request.getContent() 40 | .map(s -> { 41 | boolean throwException = Boolean.valueOf(request.getQueryParameters().get("throw_exception").get(0)); 42 | int delayBy = Integer.valueOf(request.getQueryParameters().get("delay_by").get(0)); 43 | String msg = request.getQueryParameters().get("message").get(0); 44 | Message message = new Message("id", msg, throwException, delayBy); 45 | return message; 46 | }) 47 | .flatMap(message -> { 48 | logger.info("About to make remote call"); 49 | Observable resp1 = new CachedClientCommand(this.remoteCallService, message).observe(); 50 | Observable resp2 = new CachedClientCommand(this.remoteCallService, message).observe(); 51 | return resp1.mergeWith(resp2); 52 | 53 | }) 54 | .flatMap(ack -> { 55 | try { 56 | return response.writeStringAndFlush(objectMapper.writeValueAsString(ack)); 57 | } catch (Exception e) { 58 | response.setStatus(HttpResponseStatus.BAD_REQUEST); 59 | return response.close(); 60 | } finally { 61 | context.shutdown(); 62 | } 63 | } 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.bk 7 | sample-hystrix-dashboard 8 | 1.0.0-SNAPSHOT 9 | jar 10 | 11 | sample-hystrix-dashboard 12 | Sample Hystrix Dashboard 13 | 14 | 15 | org.springframework.cloud 16 | spring-cloud-starter-parent 17 | Brixton.M1 18 | 19 | 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | 27 | org.springframework.cloud 28 | spring-cloud-starter 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-hystrix 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-starter-hystrix-dashboard 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-config-client 41 | 42 | 43 | org.springframework.cloud 44 | spring-cloud-starter-eureka 45 | 46 | 47 | org.springframework.cloud 48 | spring-cloud-starter-feign 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-starter-ribbon 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-web 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-actuator 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | test 66 | 67 | 68 | org.webjars 69 | bootstrap 70 | 3.3.4 71 | 72 | 73 | org.webjars 74 | angularjs 75 | 1.3.15 76 | 77 | 78 | org.webjars 79 | angular-ui-router 80 | 0.2.13 81 | 82 | 83 | org.webjars 84 | jquery 85 | 2.1.1 86 | 87 | 88 | com.netflix.archaius 89 | archaius-core 90 | 91 | 92 | 93 | 94 | 95 | org.springframework.boot 96 | spring-boot-maven-plugin 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /aggregate/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /service1/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /sample-load-test/src/test/resources/gatling.conf: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Gatling Configuration # 3 | ######################### 4 | 5 | # This file contains all the settings configurable for Gatling with their default values 6 | 7 | gatling { 8 | core { 9 | #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp) 10 | #runDescription = "" # The description for this simulation run, displayed in each report 11 | #encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation 12 | #simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated) 13 | #mute = false # When set to true, don't ask for simulation name nor run description (currently only used by Gatling SBT plugin) 14 | 15 | extract { 16 | regex { 17 | #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching 18 | } 19 | xpath { 20 | #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching 21 | } 22 | jsonPath { 23 | #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching 24 | #preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations 25 | jackson { 26 | #allowComments = false # Allow comments in JSON files 27 | #allowUnquotedFieldNames = false # Allow unquoted JSON fields names 28 | #allowSingleQuotes = false # Allow single quoted JSON field names 29 | } 30 | 31 | } 32 | css { 33 | #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching 34 | } 35 | } 36 | 37 | timeOut { 38 | #simulation = 8640000 # Absolute timeout, in seconds, of a simulation 39 | } 40 | directory { 41 | #data = user-files/data # Folder where user's data (e.g. files used by Feeders) is located 42 | #bodies = user-files/bodies # Folder where bodies are located 43 | #simulations = user-files/simulations # Folder where the bundle's simulations are located 44 | #reportsOnly = "" # If set, name of report folder to look for in order to generate its report 45 | #binaries = "" # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target. 46 | #results = results # Name of the folder where all reports folder are located 47 | } 48 | } 49 | charting { 50 | #noReports = false # When set to true, don't generate HTML reports 51 | #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports 52 | #accuracy = 10 # Accuracy, in milliseconds, of the report's stats 53 | indicators { 54 | #lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary 55 | #higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary 56 | #percentile1 = 50 # Value for the 1st percentile to track in the reports, the console summary and GraphiteDataWriter 57 | #percentile2 = 75 # Value for the 2nd percentile to track in the reports, the console summary and GraphiteDataWriter 58 | #percentile3 = 95 # Value for the 3rd percentile to track in the reports, the console summary and GraphiteDataWriter 59 | #percentile4 = 99 # Value for the 4th percentile to track in the reports, the console summary and GraphiteDataWriter 60 | } 61 | } 62 | http { 63 | #elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable 64 | #rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable 65 | #fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable 66 | #fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable 67 | #redirectPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent redirects, set to 0 to disable 68 | #expirePerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Expire' headers, set to 0 to disable 69 | #lastModifiedPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Last-Modified' headers, set to 0 to disable 70 | #etagPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent ETag headers, set to 0 to disable 71 | #warmUpUrl = "http://gatling.io" # The URL to use to warm-up the HTTP stack (blank means disabled) 72 | #enableGA = true # Very light Google Analytics, please support 73 | ssl { 74 | trustStore { 75 | #type = "" # Type of SSLContext's TrustManagers store 76 | #file = "" # Location of SSLContext's TrustManagers store 77 | #password = "" # Password for SSLContext's TrustManagers store 78 | #algorithm = "" # Algorithm used by SSLContext's TrustManagers store 79 | } 80 | keyStore { 81 | #type = "" # Type of SSLContext's KeyManagers store 82 | #file = "" # Location of SSLContext's KeyManagers store 83 | #password = "" # Password for SSLContext's KeyManagers store 84 | #algorithm = "" # Algorithm used SSLContext's KeyManagers store 85 | } 86 | } 87 | ahc { 88 | #allowPoolingConnections = true # Allow pooling HTTP connections (keep-alive header automatically added) 89 | #allowPoolingSslConnections = true # Allow pooling HTTPS connections (keep-alive header automatically added) 90 | #compressionEnforced = false # Enforce gzip/deflate when Accept-Encoding header is not defined 91 | #connectTimeout = 60000 # Timeout when establishing a connection 92 | #pooledConnectionIdleTimeout = 60000 # Timeout when a connection stays unused in the pool 93 | #readTimeout = 60000 # Timeout when a used connection stays idle 94 | #connectionTTL = -1 # Max duration a connection can stay open (-1 means no limit) 95 | #ioThreadMultiplier = 2 # Number of Netty worker threads per core 96 | #maxConnectionsPerHost = -1 # Max number of connections per host (-1 means no limit) 97 | #maxConnections = -1 # Max number of connections (-1 means no limit) 98 | #maxRetry = 0 # Number of times that a request should be tried again 99 | #requestTimeout = 60000 # Timeout of the requests 100 | #useProxyProperties = false # When set to true, supports standard Proxy System properties 101 | #webSocketTimeout = 60000 # Timeout when a used websocket connection stays idle 102 | #useRelativeURIsWithConnectProxies = true # When set to true, use relative URIs when talking with an SSL proxy or a WebSocket proxy 103 | #acceptAnyCertificate = true # When set to true, doesn't validate SSL certificates 104 | #httpClientCodecMaxInitialLineLength = 4096 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") 105 | #httpClientCodecMaxHeaderSize = 8192 # Maximum size, in bytes, of each request's headers 106 | #httpClientCodecMaxChunkSize = 8192 # Maximum length of the content or each chunk 107 | #keepEncodingHeader = true # Don't drop Encoding response header after decoding 108 | #webSocketMaxFrameSize = 10240 # Maximum frame payload size 109 | #httpsEnabledProtocols = "" # Comma separated enabled protocols for HTTPS, if empty use the JDK defaults 110 | #httpsEnabledCipherSuites = "" # Comma separated enabled cipher suites for HTTPS, if empty use the JDK defaults 111 | #sslSessionCacheSize = 20000 # SSLSession cache size (set to 0 to disable) 112 | #sslSessionTimeout = 86400 # SSLSession timeout (default is 24, like Hotspot) 113 | } 114 | } 115 | data { 116 | #writers = "console, file" # The lists of DataWriters to which Gatling write simulation data (currently supported : "console", "file", "graphite", "jdbc") 117 | #reader = file # The DataReader used by the charting engine for reading simulation results 118 | console { 119 | #light = false # When set to true, displays a light version without detailed request stats 120 | } 121 | file { 122 | #bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes 123 | } 124 | leak { 125 | #noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening 126 | } 127 | jdbc { 128 | db { 129 | #url = "jdbc:mysql://localhost:3306/temp" # The JDBC URL used by the JDBC DataWriter 130 | #username = "root" # The database user used by the JDBC DataWriter 131 | #password = "123123q" # The password for the specified user 132 | } 133 | #bufferSize = 20 # The size for each batch of SQL inserts to send to the database 134 | create { 135 | #createRunRecordTable = "CREATE TABLE IF NOT EXISTS `RunRecords` ( `id` INT NOT NULL AUTO_INCREMENT , `runDate` DATETIME NULL , `simulationId` VARCHAR(45) NULL , `runDescription` VARCHAR(45) NULL , PRIMARY KEY (`id`) )" 136 | #createRequestRecordTable = "CREATE TABLE IF NOT EXISTS `RequestRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenario` varchar(45) DEFAULT NULL, `userId` VARCHAR(30) NULL, `name` varchar(50) DEFAULT NULL, `requestStartDate` bigint DEFAULT NULL, `requestEndDate` bigint DEFAULT NULL, `responseStartDate` bigint DEFAULT NULL, `responseEndDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, `message` varchar(4500) DEFAULT NULL, `responseTime` bigint DEFAULT NULL, PRIMARY KEY (`id`) )" 137 | #createScenarioRecordTable = "CREATE TABLE IF NOT EXISTS `ScenarioRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(30) NULL, `event` varchar(50) DEFAULT NULL, `startDate` bigint DEFAULT NULL, `endDate` bigint DEFAULT NULL, PRIMARY KEY (`id`) )" 138 | #createGroupRecordTable = "CREATE TABLE IF NOT EXISTS `GroupRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(30) NULL, `entryDate` bigint DEFAULT NULL, `exitDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, PRIMARY KEY (`id`) )" 139 | } 140 | insert { 141 | #insertRunRecord = "INSERT INTO RunRecords (runDate, simulationId, runDescription) VALUES (?,?,?)" 142 | #insertRequestRecord = "INSERT INTO RequestRecords (runId, scenario, userId, name, requestStartDate, requestEndDate, responseStartDate, responseEndDate, status, message, responseTime) VALUES (?,?,?,?,?,?,?,?,?,?,?)" 143 | #insertScenarioRecord = "INSERT INTO ScenarioRecords (runId, scenarioName, userId, event, startDate, endDate) VALUES (?,?,?,?,?,?)" 144 | #insertGroupRecord = "INSERT INTO GroupRecords (runId, scenarioName, userId, entryDate, exitDate, status) VALUES (?,?,?,?,?,?)" 145 | } 146 | } 147 | graphite { 148 | #light = false # only send the all* stats 149 | #host = "localhost" # The host where the Carbon server is located 150 | #port = 2003 # The port to which the Carbon server listens to 151 | #protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp") 152 | #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite 153 | #bufferSize = 8192 # GraphiteDataWriter's internal data buffer size, in bytes 154 | #writeInterval = 1 # GraphiteDataWriter's write interval, in seconds 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /sample-hystrix-dashboard/src/main/resources/static/fonts/glyphicons-halflings-regular.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | --------------------------------------------------------------------------------