Spring Boot + Eureka Server + Hystrix with Turbine: empty turbine.stream
Solution 1
It works for me if I add some configuration for the cluster, e.g.
turbine:
appConfig: customers,stores
clusterNameExpression: new String('default')
Turbine has to know how to construct the "cluster" name (an aggregation key for sets of applications). The default is to use the appname, so if you don't set the clusterNameExpression
you need to use a query param in the stream URL, e.g. /turbine.stream?cluster=CUSTOMERS
(uppercased appname).
Solution 2
In my case I had :7979/mock.stream as client for testing turbine app. The turbine checks time of event (timeOfEvent) so it will show only the current date time events.
It can be turned off using
turbine.InstanceMonitor.eventStream.skipLineLogic.enabled = false
Related videos on Youtube
Szymon Stepniak
🔑 30BA 1AAD 71C2 08A2 4C74 5902 FBF5 76F4 BFA5 573B 🖳 Freelancer ☕ Toruń Java User Group founder 📽️ YouTube content creator ## 🏆 A few comments about my contributions: "This is a very good answer. (...) It is actually too good and extensive for the little effort the OP put into his question. Anyway, big compliment to Szymon." - link "Awesome analysis, thank you!" - link "Perfect, helps and explains a few more related items." - link "This is awesome! It works :)" - link "you are a genius :)" - link "god dont you just have to love stack overflow - absolutely brilliant. Works a treat i can take it from here." - link ## Is there anything I can help you with? 📧 szymon[dot]stepniak[at]gmail[dot]com
Updated on August 29, 2020Comments
-
Szymon Stepniak over 3 years
I'm trying to run Spring Boot (with Spring Cloud) + Eureka Server + Hystrix Dashboard and Turbine stream, but I run into a problem I couldn't find any solution so far. I use Spring Boot 1.2.1.RELEASE and Spring Cloud 1.0.0.RC2. Here is what I have:
The first instance is running Eureka server and Hystrix dashboard:
@Configuration @EnableAutoConfiguration @EnableEurekaServer @EnableHystrixDashboard @EnableDiscoveryClient class Application { public static void main(String[] args) { SpringApplication.run Application, args } }
Here you can find
build.gradle
for that instance - https://gist.github.com/wololock/570272ad7cf2d14a4d3cEureka server is running ok, I can see registered instances on eureka server dashboard, I can also use
LoadBalancer
to get the URL to registered instance using its id. So far everything is ok.I have a few instances that are run with
@EnableHystrix
annotation and use@HystrixCommand
to define which methods have to be monitored by Hystrix. When I pass URL to hystrix.stream of single instance to Hystrix dashboard, I can see it running with no problem.I have also separate Turbine server, not complicated one:
@EnableAutoConfiguration @EnableTurbine @Configuration @EnableDiscoveryClient class Application { public static void main(String[] args) { SpringApplication.run Application, args } }
Here you can find
build.gradle
for Turbine server instance - https://gist.github.com/wololock/ff0d855b8a890232851eIt uses very simple configuration, build mostly on the one provided by sample turbine app - https://github.com/spring-cloud-samples/turbine
info: component: Turbine endpoints: restart: enabled: true shutdown: enabled: true turbine: appConfig: pdf-creator-service InstanceDiscovery: impl: io.spring.platform.netflix.turbine.EurekaInstanceDiscovery server: port: 8989 management: port: 8990 eureka: instance: leaseRenewalIntervalInSeconds: 10 client: serviceUrl: defaultZone: ${vcap.services.${PREFIX:}eureka.credentials.uri:http://user:password@localhost:8761}/eureka/
After running those instances in order:
- eureka server
- turbine server
- discover client instance,
I have 2nd and 3rd instance registered in eureka server, turbine server log says, that there is one instance up:
[2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instance list for apps: [pdf-creator-service] [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instances for app: pdf-creator-service [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Retrieved hosts from InstanceDiscovery: 1 [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Found hosts that have been previously terminated: 0 [2015-02-06 12:35:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Hosts up:1, hosts down: 0 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instance list for apps: [pdf-creator-service] [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instances for app: pdf-creator-service [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Retrieved hosts from InstanceDiscovery: 1 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Found hosts that have been previously terminated: 0 [2015-02-06 12:36:04.162] boot - 20495 INFO [Timer-0] --- InstanceObservable: Hosts up:1, hosts down: 0
Calling hystrix.stream from a single instance works, e.g.
curl http://localhost:8885/hystrix.stream
returns:data: {"type":"HystrixCommand","name":"post","group":"PdfController","currentTime":1423223614259,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountCollapsedRequests":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":0,"rollingCountFallbackFailure":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":0,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"latencyExecute_mean":0,"latencyExecute":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"latencyTotal_mean":0,"latencyTotal":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":8000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1} data: {"type":"HystrixCommand","name":"generate","group":"WkHtmlToPdfGenerator","currentTime":1423223614259,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountCollapsedRequests":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":0,"rollingCountFallbackFailure":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":0,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"latencyExecute_mean":0,"latencyExecute":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"latencyTotal_mean":0,"latencyTotal":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":8000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1} data: {"type":"HystrixThreadPool","name":"PdfController","currentTime":1423223614259,"currentActiveCount":0,"currentCompletedTaskCount":4,"currentCorePoolSize":10,"currentLargestPoolSize":4,"currentMaximumPoolSize":10,"currentPoolSize":4,"currentQueueSize":0,"currentTaskCount":4,"rollingCountThreadsExecuted":0,"rollingMaxActiveThreads":0,"propertyValue_queueSizeRejectionThreshold":5,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"reportingHosts":1}
But when I attach turbine.stream to hystrix dashboard, I get nothing. Logs say:
[2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- InstanceObservable: Retrieved hosts from InstanceDiscovery: 1 [2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- InstanceObservable: Found hosts that have been previously terminated: 0 [2015-02-06 12:42:48.922] boot - 24816 INFO [Timer-0] --- InstanceObservable: Hosts up:1, hosts down: 0 [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamServlet: FilterCriteria: [] [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamServlet: StatsType filters: [] [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamingConnection: Relevance config: [] [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineStreamingConnection: Relevance metrics config: {} [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- ClusterMonitor: Registering event handler for cluster monitor: StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b [2015-02-06 12:43:26.237] boot - 24816 INFO [XNIO-2 task-4] --- TurbineDataDispatcher: Just added and starting handler tuple: StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b [2015-02-06 12:43:26.238] boot - 24816 INFO [XNIO-2 task-4] --- AggDataFromCluster: Per handler dispacher started for: StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b [2015-02-06 12:43:26.238] boot - 24816 INFO [XNIO-2 task-4] --- ClusterMonitor: All event handlers for cluster monitor: [StreamingHandler_637572ab-acda-4bf4-81cd-6a658adb73eb, StreamingHandler_f1308dda-58c5-47a5-b1e2-5a0bea32226b, StaticListener_For_Aggregator, StreamingHandler_5ec12ee8-3fcd-4a6f-9006-d2a6ecc309d0, StreamingHandler_72d7b9e2-ad98-42a0-9ac3-abe4aa57cc7a] [2015-02-06 12:43:26.238] boot - 24816 INFO [XNIO-2 task-4] --- ClusterMonitor: Starting up the cluster monitor for default_agg
If I do
curl http://localhost:8989/turbine.stream
I get only:: ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223006935} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223010935} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223013936} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223017936} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223020937} : ping : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223024937} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223028938} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223032938} : ping : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223036938} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223039939} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223043939} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223046940} : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223050940} : ping : ping data: {"reportingHostsLast10Seconds":0,"name":"meta","type":"meta","timestamp":1423223054941}
My question is: do I missed something in setting it up and running? Previously I tried to manage this by having eureka and turbine server in single instance, but in that case turbine couldn't even find the registered application in eureka using proper application name. I made a progress after splitting eureka and turbine, but it still does not work correctly.
I will be grateful for any suggestion. If you need more information, just let me know, I might miss something important.
UPDATE 20150209
Following Dave's suggestion I applied small changes in
application.yml
file ofturbine-server
. Now the file contains only:info: component: Turbine turbine: appConfig: pdf-creator-service clusterNameExpression: 'default' server: port: 8989 management: port: 8990 eureka: instance: leaseRenewalIntervalInSeconds: 10 client: serviceUrl: defaultZone: ${vcap.services.${PREFIX:}eureka.credentials.uri:http://user:password@localhost:8761}/eureka/
But it doesn't make turbine.stream working. After turbine-server gets aware of registered client in eureka server, it fails with given exception:
[2015-02-09 21:25:03.516] boot - 4808 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instance list for apps: [pdf-creator-service] [2015-02-09 21:25:03.516] boot - 4808 INFO [Timer-0] --- EurekaInstanceDiscovery: Fetching instances for app: pdf-creator-service [2015-02-09 21:25:03.516] boot - 4808 INFO [Timer-0] --- EurekaInstanceDiscovery: Received instance list for app: pdf-creator-service = 1 [2015-02-09 21:25:03.520] boot - 4808 ERROR [Timer-0] --- EurekaInstanceDiscovery: Failed to fetch instances for app: pdf-creator-service, retrying once more org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'default' cannot be found on object of type 'com.netflix.appinfo.InstanceInfo' - maybe not public? at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:226) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:93) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81) at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.getClusterName(EurekaInstanceDiscovery.java:183) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.marshallInstanceInfo(EurekaInstanceDiscovery.java:141) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.getInstancesForApp(EurekaInstanceDiscovery.java:123) at org.springframework.cloud.netflix.turbine.EurekaInstanceDiscovery.getInstanceList(EurekaInstanceDiscovery.java:88) at com.netflix.turbine.discovery.InstanceObservable.getInstanceList(InstanceObservable.java:327) at com.netflix.turbine.discovery.InstanceObservable.access$500(InstanceObservable.java:66) at com.netflix.turbine.discovery.InstanceObservable$1.run(InstanceObservable.java:258) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
I tried writting
'default'
as well asdefault
, but the result is unfortunately the same.Solution
Thanks Dave Syer for finding the proper solution. Basically what did the trick was adding:
turbine: clusterNameExpression: new String("default")
to
application.yml
file in turbine server application instance. It might look weird, I didn't believe it will work, but it does. Now when I call my hystrix client application I get the proper information inhystrix.stream
that is served by this application and inturbine.stream
of Turbine server as well. My currentapplication.yml
in turbine server looks as follows:info: component: Turbine turbine: clusterNameExpression: new String("default") appConfig: pdf-creator-service server: port: 8989 management: port: 8990 eureka: instance: leaseRenewalIntervalInSeconds: 10 client: serviceUrl: defaultZone: ${vcap.services.${PREFIX:}eureka.credentials.uri:http://user:password@localhost:8761}/eureka/
turbine.appConfig
holds the information about the hystrix clients (by their IDs). To add another client to your turbine server you will have to simply put another instance id, coma separated with the previous one. And that's all folks :)-
Dave Syer about 9 yearsI can reproduce the problem at least (see simple sample at github.com/spring-cloud-samples/tests/tree/master/turbine in the test source). I'll have a closer look next week. Maybe Spencer will be able to comment before then.
-
Szymon Stepniak about 9 yearsThanks for your interest Dave. I will also try to dig into and find something more to help in finding solution for that issue.
-
spencergibb about 9 yearsI don't think
'default'
will work. The SPEL expression must evaluate to a property on a Netflix InstanceInfo. Looking now. -
spencergibb about 9 yearsI see why
'default'
works. You don't haveturbine.aggregator.clusterConfig
defined. Define it to be the uppercase name of you app (what you see in eureka) and removeclusterNameExpression
. -
Dave Syer about 9 yearsThat would work too, but then you need "cluster=APPNAME" in the stream url.
-
Szymon Stepniak about 9 yearsHey Spencer, thanks for your suggestion. I tried the approach with
turbine.aggregator.clusterConfig
, but the result was the same (I did query the url with additional?cluster=[CLUSTERNAME]
parameter, it failed without it anyway). -
Marcin Grzejszczak almost 9 yearsI've managed to make it work also with the
new String('default')
but it puzzles me that providing explicit clusters doesn't seem to work at all. -
Yonatan almost 8 yearsPlease note that the documentation says you should double quote the expression. That is, you should write
clusterNameExpression: "'default'"
. cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html. Please consider to re-edit the answer... -
PAA almost 4 yearsCould you pls guide me here stackoverflow.com/questions/61444872/… ?
-
Szymon Stepniak about 9 yearsHey Dave, I tried out adding
clusterNameExpression: 'default'
to theapplication.yml
in turbine server, but it didnt help and cause an exception. I updated initial post with all details. -
Dave Syer about 9 yearsEscaping the quotes seems to be a problem. It worked for me. Maybe try
new String('default')
? -
Szymon Stepniak about 9 yearsI must admit, that I didn't believe that using
new String('default')
might change, but it actually did the trick :) Thank you @DaveSyer for your help, I can now move forward and put myself into new troubles :) -
Christian over 8 yearsfinding this answer after months. ;) new String('default') works for me as well. Please consider editing the original answer!!
-
Praveen_Shukla over 7 years@SzymonStepniak: where should we place the application.yml file. In the application code or turbine server ?
-
Szymon Stepniak over 7 years@Praveen_Shukla In standard path -
src/main/resources
-
Praveen_Shukla over 7 years@SzymonStepniak: thanks for quick rply. one more question should It be on turbine project or my application project ?
-
Szymon Stepniak over 7 years@Praveen_Shukla In Turbine project
-
PAA about 4 years@DaveSyer - Could you please guide me here: stackoverflow.com/questions/61431036/… ?