SpringCloud Netflix etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
SpringCloud Netflix etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

27 Eylül 2021 Pazartesi

SpringCloud Netflix Eureka Kullanımı

Giriş
Eureka iki kısımdan oluşur
1. Sunucu
2. İstemci

Eureka Sunucusu
Eureka kullanabilmek için bir tane Eureka sunucusu başlatmak gerekir. Bunun için @EnableEurekaServer anotasyonu kullanılır

Eureka İstemcisi
İstemcilerin bu sunucuyu kullanabilmesi için @EnableEurekaClient anotasyonu kullanılır.  Bu anotasyon aslında mecburi değil. Açıklaması şöyle
Then we need to annotate a @Configuration with either @EnableDiscoveryClient or @EnableEurekaClient – note that this annotation is optional if we have the spring-cloud-starter-netflix-eureka-client dependency on the classpath.
Health Monitoring
Kullanılabilecek iki tane yöntem var. Açıklaması şöyle
Learnt Monitoring for the approach where servers send keep-alive requests to clients in order to learn whether they are healthy; 
Taught Monitoring for the approach where clients send heartbeats to servers in order to educate the server on their health status.
Eureka'ya kayıtlı istemci durumunu heartbeat mesajı ile kendisi bildirir. Yani Eurekea Taught Monitoring yöntemini kullanır. 

Eurekea sunucusu ile istemciyi kontrol etmez ama Learnt Monitoring için gerekli URL'yi sağlar. Şeklen şöyle



Heartbeat URL
Eureka sunucusu heartbeat için şu URL'yi dinler
PUT /eureka/apps/{app-id}/{instance-id}?status={status}
Açıklaması şöyle
I’ve omitted a few other query parameters for clarity. {instance-id} takes the form of hostname:app-id:port where it identifies a unique Eureka client instance. Eureka server recognizes a few statuses — UP, DOWN, STARTING, OUT_OF_SERVICE and UNKNOWN.
Örnek bir hearbeat şöyle
PUT /eureka/apps/ORDER-SERVICE/localhost:order-service:8886?status=UP
Açıklaması şöyle. Yani istemci henüz Eureka sunucusuna kayıt olmadıysa, 404 gönderilir ve heartbeat mesajı kabul edilmez. Önce kayıt olması istenir
Upon receiving a heartbeat request from a client instance, Eureka server renews the lease of that instance. If it’s the very first heartbeat from a given client, Eureka server responds with a 404 and right after that the client will send a registration request.
Sorgulama URL'si
Sorgulama için URL şöyle
PUT    /eureka/apps/{app-id}/
Örnek
Şöyle yaparız
GET /eureka/apps/ORDER-SERVICE
<application>
  <name>ORDER-SERVICE</name>
  <instance>
    <instanceId>localhost:order-service:8886</instanceId>
    <ipAddr>192.168.1.6</ipAddr>
    <port>8886</port>
    <status>UP</status>
    <overriddenstatus>UP</overriddenstatus>
    <healthCheckUrl>http://localhost:8886/health</healthCheckUrl>
    ...
    ...
  </instance>
</application>
Cevap'taki alanlar için açıklama şöyle
The response has three important health-related information — status, overriddenstatus and healthCheckUrl.

status is the health status as published by the Eureka instance itself.

overriddenstatus is the enforced health status manually or by tools. The PUT /eureka/apps/{app-id}/instance-id}/status?value={status} operation is used to override the status published by Eureka instance and once invoked both status will also be changed to the overriddenstatus.

healthCheckUrl is the endpoint which the client exposes to GET its health status
Örnek - Ribbon
Bu bilgiyi sorgulayan ve kullanan Ribbon için açıklama şöyle
This information can be leveraged by tools for various purposes.

Client-side load balancers like Ribbon to make load balancing decisions
Ribbon reads the status attribute and considers only the instances with UP status for load balancing. Ribbon, however, does not invoke the healthCheckUrl but relies on published instance status available in the registry.
Şeklen şöyle


Örnek - Asgard
Bu bilgiyi sorgulayan ve kullanan Asgard için açıklama şöyle
Deployment tools like Asgard to make deployment decisions
During rolling deployments, Asgard first deploys one instance of the new version of a microservice and waits till that instance is transitioned to UP status - before deploying rest of the instances (as a risk mitigation strategy). However, rather than relying on instance status available in the Eureka server registry (i.e. the status attribute), Asgard learns instance status by invoking its healthCheckUrl. It could be because the value of status attribute can be stale (since it’s dependent on a few factors as described in the next section) but live health status is important in this case in order to avoid deployment delays.
Şeklen şöyle



Accuracy of health status
Açıklaması şöyle. Yani Eureka her zaman en son sonucu vermeyebilir. Biraz gecikme olabilir.
The Eureka server registry (hence the health status) is not always accurate due to the following reasons.

AP in CAP
Eureka is a highly available system in terms of CAP theorem, the information in the registry may not be consistent between Eureka servers in the cluster — during a network partition.

Server response cache
Eureka servers maintain a response cache which is updated in every 30 seconds by default. Therefore an instance which is actually DOWN may appear to be UP in the GET /eureka/apps/{app-id}/ response.

Scheduled heartbeats
Since the Eureka clients send heartbeats in every 30 seconds by default, health status changes between the heartbeats are not reflected in the Eureka server registry.

Self preservation
Eureka servers stop expiring clients from the registry when they do not receive heartbeats beyond a certain threshold which in turn makes the registry inaccurate.
Therefore the clients should follow proper failover mechanisms to complement this inaccuracy.

Manual İşlem İçin Diğer URL'ler
Bunlar şöyle
PUT    /eureka/apps/{app-id}/{instance-id}/status?value={status}
DELETE /eureka/apps/{app-id}/{instance-id}/status
PUT İle Manual İşlem
Açıklaması şöyle
The overriding operation (i.e. the PUT operation above) is used to take otherwise a healthy instance OUT_OF_SERVICE manually or by administration tools such as Asgard, in order to temporarily disallow traffic to some instance.
Örnek şöyle yaparız
PUT /eureka/apps/ORDER-SERVICE/localhost:order-service:8886/status?value=OUT_OF_SERVICE
Açıklaması şöyle
This will be useful for red black deployments where you run older and newer versions of a microservice for some period of time (in order to easily rollback to an older version if the new version is unstable). Once the deployment of the new version is completed and the new version has started serving requests, instances of the older version can be taken OUT_OF_SERVICE (without bringing them down) so that they will just stop serving requests.
DELETE İle Manual İşlem
Şöyle yaparız
DELETE /eureka/apps/ORDER-SERVICE/localhost:order-service:8886/status
HealthCheckHandler Arayüzü
Açıklaması şöyle
Eureka clients (or servers) never invoke the /health endpoint to determine the health status of an instance. Health status of a Eureka instance is determined by a HealthCheckHandler implementation. The default HealthCheckHandler always announces that the application is in UP state as long as the application is running.

Eureka allows custom HealthCheckHandlers to be plugged-in through the EurekaClient#registerHealthCheck() API. Spring Cloud leverages this extension point to register a new handler, EurekaHealthCheckHandler, if the following property is set.

eureka.client.healthcheck.enabled=true
EurekaHealthCheckHandler 
Açıklaması şöyle
The EurekaHealthCheckHandler works by aggregating health status from multiple health indicators such as;

- DiskSpaceHealthIndicator
- RefreshScopeHealthIndicator
- HystrixHealthIndicator

and mapping the aggregated status into one of Eureka supported statuses. This status will then be propagated to Eureka server through heartbeats.
application.properties
eureka.instance.health-check-url Alanı
Spring sayfasındaki açıklama şöyle
Gets the absolute health check page URL for this instance. The users can provide the healthCheckUrlPath if the health check page resides in the same instance talking to eureka, else in the cases where the instance is a proxy for some other server, users can provide the full URL. If the full URL is provided it takes precedence.
Daha anlaşılır bir açıklama şöyle. Yani Eureka istemcisi, sunucuya kayıt olurken bir URL vermek zorunda. Bu URL'nin ne olacağına health-check-url ve health-check-url-path alanlarına bakarak karakr veriyor. Eğer bu alanlara değer vermezsek /health kullanılıyor. 
Eureka clients POST a healthCheckUrl in the payload when they are registering themselves with the server. The value of the healthCheckUrl is calculated from the following instance
 properties.

eureka.instance.health-check-url=...
eureka.instance.health-check-url-path=...


The default value of the health-check-url-path is /health which is the spring-boot’s default health actuator endpoint that will be ignored if a heath-check-url property is set.
Örnek - custom path
Şöyle yaparız
endpoints.health.path=/new-heath

# configure either a relative path
eureka.instance.health-check-url-path=${endpoints.health.path}

# or an absolute path
eureka.instance.health-check-url=http://${eureka.hostname}:${server.port}/${endpoints.health.path}
Örnek - custom path
Şöyle yaparız
management.context-path=/admin

# configure either a relative path
eureka.instance.health-check-url-path=${management.context-path}/health

# or an absolute path
eureka.instance.health-check-url=http://${eureka.hostname}:${server.port}/${management.context-path}/health





SpringCloud Netflix Zuul @EnableZuulProxy Anotasyonu

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
Açıklaması şöyle
This annotation is used to make a spring boot application act as a Zuul server. 
Bu anotasyon ile Zuul kendisine gelen "http://localhost:9002/service-sample/ping" şeklindeki bir isteği Eureka'ya "service-sample" ismi ile kaydolmuş düğümlerden birisine yönlendirir ve onun "/ping" rest endpoint'ini çağırır.

Örnek
Şöyle yaparız
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class CloudZuulApplication {
  public static void main(String[] args) {
    SpringApplication.run(CloudZuulApplication.class, args);
  }
}
application.properties dosyasını şöyle yaparız
# Specify application name, and port on which this app should run
spring.application.name=cloud-zuul
server.port=9002

# Set Eureka server url here
eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka
Örnek
Şöyle yaparız
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class SuperdevZuulApplication {
  public static void main(String[] args) {
    SpringApplication.run(SuperdevZuulApplication.class, args);
  }
  @Bean
  public SimpleFilter simpleFilter() {
  return new SimpleFilter();
  }
}
application.properties dosyasını şöyle yaparız
server.port=8081
eureka.client.serviceUrl.defaultZone=${EUREKA_SERVER:http://localhost:8761/eureka}
spring.application.name=superdev-zuul

zuul.routes.customer.url=http://localhost:8080

ribbon.eureka.enabled=false
Açıklaması şöyle. Burada aslında zuul.routes kullanmaya normalde gerek yok, çünkü amaç zaten Eureka Discovery ile Rest servisini bulmak. Ancak ben yine de örnek olsun diye aldım
zuul.routes — we are mapping ZUUL to our customer service, any request that starts with a http://localhost:8081/customer will redirect to the customer’s service
ribbon.eureka.enabled — at this point we disabled the load balancing
customer Rest microservice'i tetiklemek için şöyle yaparız. 
http://localhost:8081/customer/v1/api/customer
Bu da aslında şuraya redirect edilir.
http://localhost:8080/customer/v1/api/customer
Örnek
Şöyle yaparız. Burada ribbon ile client side load balancing halen kullanılıyor.
server:
  port: 8000
zuul:
  ignoredServices: ‘*’
  prefix: /api
  routes:
    route1:
      path: /route1/**
      serviceId: <service-id-given-in-bootstrap>
      strip-prefix: false
    
    route2:
      path: /route2/**
      serviceId: <service-id-given-in-bootstrap>
      strip-prefix: false
    route3:
      path: /route3/**
      serviceId: <service-id-given-in-bootstrap>
      strip-prefix: false
endpoints:
  trace:
    sensitive: false
eureka:
  client:
    service-url:
       default-zone: http://localhost:8761/eureka/


2 Ağustos 2021 Pazartesi

SpringCloud Netflix Hystrix Dashboard

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
Örnek
Şöyle yaparız
@SpringBootApplication
@EnableHystrixDashboard
@EnableCircuitBreaker
public class ProductsConsumerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ProductsConsumerApplication.class, args);
  }
}
Açıklaması şöyle
@EnableHystrix is optional. @EnableCircuitBreaker will scan the classpath for any compatible Circuit Breaker implementation, if Hystrix is in classpath then we need not explicitly enable Hystrix.

@EnableHystrixDashboard adds one useful dashboard running on localhost provided by Hystrix to monitor its status.
Dashboard'a bakmak için http://localhost:8080/hystrix adresine gideriz.

3 Mart 2021 Çarşamba

SpringCloud Netflix Hystrix Kullanımı - Circuit Breaker İçindir - Kullanmayın

Giriş
Açıklaması şöyle
Hystrix is a fault tolerance java library. This tool is designed to separate points of access to remote services, systems, and 3rd-party libraries in a distributed environment like Microservices. It improves overall system by isolating the failing services and preventing the cascading effect of failures.
Açıklaması şöyle.
If you are using Spring cloud for communication between microservices, you may leverage Spring Cloud Netflix Hystrix or Spring Cloud Circuit Breaker to implement circuit breaking. However, the first solution has been already moved to the maintenance mode by the Pivotal team, since Netflix does not develop Hystrix anymore. The recommended solution is the new Spring Cloud Circuit Breaker built on top of the resilience4j project.
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>2.2.2.RELEASE</version>
</dependency>
İki tane önemli anotasyon var.
1. @EnableHystrix

9 Şubat 2021 Salı

SpringCloud Netflix Eureka DiscoveryClient Sınıfı

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.client.discovery.DiscoveryClient;
getInstances metodu - service name
Örnek
Şöyle yaparız
public static final String URL_DISCOVER_BOOKS = "%s/books?bridgeEndpoint=true";

@Autowired
private DiscoveryClient discoveryClient;

String.format(URL_DISCOVER_BOOKS,
discoveryClient.getInstances("discovery-client").get(0).getUri());
Örnek
Şöyle yaparız
// (Need!!) eureka.client.fetchRegistry=true
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
 
if (instances == null || instances.isEmpty()) {
  return "No instances for service: " + serviceId;
}
String html = "<h2>Instances for Service Id: " + serviceId + "</h2>";
 
for (ServiceInstance serviceInstance : instances) {
  html += "<h3>Instance: " + serviceInstance.getUri() + "</h3>";
  html += "Host: " + serviceInstance.getHost() + "<br>";
  html += "Port: " + serviceInstance.getPort() + "<br>";
}
 
return html;
getServices metodu
Tüm servis isimlerini döner. 
Şöyle yaparız
List<String> serviceIds = this.discoveryClient.getServices();

SpringCloud Netflix Eureka @EnableEurekaClient Anotasyonu - Service Registration and Discovery

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Bazı eski kodlarda şu satırı dahil ediliyor, ancak bu "...starter-eureka" yerine "...starter-netflix-eureka-client" yazmak lazım.
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
Örnek
Açıklaması şöyle
Then we need to annotate a @Configuration with either @EnableDiscoveryClient or @EnableEurekaClient – note that this annotation is optional if we have the spring-cloud-starter-netflix-eureka-client dependency on the classpath.
Şöyle yaparız. Böylece EurekaClient arayüzü veya ondan kalıtan DiscoveryClient bean kullanılabilir.
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class SpringEurekaClientApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringEurekaClientApplication.class, args);
  }
}
Örnek
Ayrıca eğer Rest Service aslında API Gateway ise şu anotasyon da gerekir
- @EnableZuulProxy

Şöyle yaparız. Bu microservice çalışınca Eureka Dashboard'da "Instances Currently Registered With Eureka" başlığı altında "superdev-crm-customer" ismi görülebilir
eureka.client.serviceUrl.defaultZone=${EUREKA_SERVER:http://localhost:8761/eureka}
spring.application.name=superdev-crm-customer
Örnek
Şöyle yaparız. 
spring:
  application:
    name: discovery-client
server:
  port: 8385
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
Eğer bu uygulamada "books" isimli bir rest noktası varsa onu görmek için Eureka sunucusuna şöyle yaparız
"discovery-client/books?bridgeEndpoint=true"
Örnek
Şöyle yaparız. Burada farklı profile isimlerine göre farklı şeyler yapılıyor.
spring:
  application:
    name: ABC-SERVICE # ==> This is Service-Id
---
# Items that apply to ALL profiles:   
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:   
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka
server:
  port: 8000  
  
---
spring:
  profiles: abc-service-replica01
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:   
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka  
server:
  port: 8001   
Örnek
Şöyle yaparız
# Set Eureka server url here, and specify Eureka instance ID generation pattern
eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka
eureka.instance.instance-id=
${spring.application.name}:${spring.application.instance_id:${random.value}}

27 Ocak 2021 Çarşamba

SpringCloud Netflix Ribbon @LoadBalanced Anotasyonu

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
Eureka Server'ı kullanarak Service Discovery yapar ve rest çağrısı yapar.  Açıklaması şöyle
@LoadBalanced is a marker annotation. It is used to indicate that RestTemplate or WebClient should use a RibbonLoadBalancerClient or LoadBalancerClient for interacting with the services. In turn, this allows you to use “logical identifiers” for the URLs we pass to the RestTemplate or WebClient. These logical identifiers are typically the name of a service registered in service discovery.

Note:- @RibbonClient(spring-cloud-starter-netflix-ribbon) and @LoadBalancerClient(spring-cloud-commons) are optional. This both works as a load-balancer on the client-side and gives us control over the HTTP and TCP clients. If we are using Service Discovery then we are good to go with default settings. we don't need to explicitly use these annotations.
Örnek
Açıklaması şöyle
Used as a marker annotation indicating that the annotated RestTemplate should use a RibbonLoadBalancerClient for interacting with your service(s).

In turn, this allows you to use "logical identifiers" for the URLs you pass to the RestTemplate. These logical identifiers are typically the name of a service. 
Şöyle yaparız. Burada some-service-name Eureka'da tanımlı logical identifier
restTemplate.getForObject("http://some-service-name/user/{id}", String.class, 1);
Örnek
Şöyle yaparız
@LoadBalanced
@Bean
RestTemplate getRestTemplate() {
  return new RestTemplate();
}
name Alanı
Açıklaması şöyle
... if we are not using any service discovery or need to customize the settings of Ribbon or LoadBalancer for a particular client then we need to use any of the two.

name - the service we are calling Ribbon or LoadBlancer but need additional customizations for how Ribbon or LoadBlancer interacts with that service.

configuration - set it to an @Configuration class with all of our customizations defined as @Beans .
Şöyle yaparız
@Configuration
@LoadBalancerClient (name ="custom-config", configuration = SomeCustomConfiguration.class)
// @RibbonClient (name = "custom-config", configuration = SomeCustomConfiguration.class)
public class WebClientConfigurationLB {

}

7 Ocak 2021 Perşembe

SpringCloud Netflix Ribbon

Giriş 
Açıklaması şöyle
Netflix Ribbon is a client-side library for load balancing. So BookMyHotel WebApp will use the Ribbon to load balance between these microservice instances, choose a microservice instance-based other on the load balancing algorithm, and connect to it. 

In Eureka Clients, a background thread runs at the client-side, connecting to the Eureka Server and retrieving the complete registry. The complete registry is cached at the client-end, so WebApp will look at its local cache to retrieve registration. Background instances thread will sync with Discovery server at the interval of 30 seconds.

If WebApp tries to connect the Registration microservice instance which is down, it will get an error. But we don’t want WebApp to fail; we want it to retry to next available instance anRibbon can configure this retryRibbon can configure this retry. We can also configure the count of retry and timeout for the same i.e. it will help BookMyHotel WebApo keep retying until some count until it finds a working instance if not found, then time out.
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
@LoadBalanced anotasyonu yazısına bakabilirsiniz

Eureka kullanarak
Şeklen şöyle


Açıklaması şöyle
This information can be leveraged by tools for various purposes.

Client-side load balancers like Ribbon to make load balancing decisions
Ribbon reads the status attribute and considers only the instances with UP status for load balancing. Ribbon, however, does not invoke the healthCheckUrl but relies on published instance status available in the registry.

Örnek - Eureka kullanmadan
application.yml şöyle olsun.  "http://ping-server/..." adresine erişince listofServers listesindeki adreslerden birisine yönlendirilir.
ping-server:
  ribbon:
    eureka:
      enabled: false
    listOfServers: localhost:9092,localhost:9999
    ServerListRefreshInterval: 15000
Şöyle yaparızz
@RestController
@RibbonClient(
  name = "ping-a-server",
  configuration = RibbonConfiguration.class)
public class ServerLocationApp {

  @LoadBalanced
  @Bean
  RestTemplate getRestTemplate() {
    return new RestTemplate();
  }

  @Autowired
  RestTemplate restTemplate;

  @RequestMapping("/server-location")
  public String serverLocation() {
    return this.restTemplate.getForObject(
      "http://ping-server/locaus", String.class);
  }
}

22 Aralık 2019 Pazar

SpringCloud Netflix Hystrix @HystrixCommand Anotasyonu - Circuit Breaker İçindir

Giriş
Açıklaması şöyle
... it will dynamically generate a proxy that will wrap the method and manage all calls through a thread pool of threads, mainly focused in handling remote calls
commandProperties - timeout
Timeout yani zaman aşımı değerini belirtmek için şuna benzer bir şey kullanılır
name = "execution.isolation.thread.timeoutInMilliseconds" value="6000"
Eğer fallback tanımlamazsak, zaman aşımı olursa şuna benzer bir hata alırız
"foo timed-out and fallback failed."
Örnek - timeout + fallback
Şöyle yaparız
@GetMapping
@HystrixCommand(
  fallbackMethod=”defaultProductList”, commandProperties = {
@HystrixProperty(name=”execution.isolation.thread.timeoutInMilliSeconds”,
value=”500”)}) 
public String cloudProductList(@PathVariable long timeout) {
  RestTemplate restTemplate = new RestTemplate();
  URI uri = URI.create("http://localhost:8080/products");
  return restTemplate.getForObject(uri, String.class);
}
  
public List<String> defaultProductList() {
  return Arrays.asList("product");
}
fallbackMethod Alanı
Örnek - timeout + fallback
Şöyle yaparız.
@SpringBootApplication
@EnableHystrix
@RestController
public class DemoHystrixApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoHystrixApplication.class, args);
  }

  @RequestMapping(value = "/")
  @HystrixCommand(fallbackMethod = "fallback", commandProperties = {
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
                     value = "1000")
  })
  public String hello() throws InterruptedException {
    Thread.sleep(3000);
    return "HELLO Hystrix";
  }

  private String fallback() {
    return "Fallback";
  }
}