From 86b1f6ede332f4d273da7e5dfad327fe0cb26b80 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 30 Jun 2017 17:10:27 -0600 Subject: [PATCH 1/4] Make aspect method public fixes gh-2063 --- .../netflix/metrics/RestTemplateUrlTemplateCapturingAspect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/metrics/RestTemplateUrlTemplateCapturingAspect.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/metrics/RestTemplateUrlTemplateCapturingAspect.java index ef353efe..18abe558 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/metrics/RestTemplateUrlTemplateCapturingAspect.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/metrics/RestTemplateUrlTemplateCapturingAspect.java @@ -26,7 +26,7 @@ import org.aspectj.lang.annotation.Aspect; @Aspect public class RestTemplateUrlTemplateCapturingAspect { @Around("execution(* org.springframework.web.client.RestOperations+.*(String, ..))") - Object captureUrlTemplate(ProceedingJoinPoint joinPoint) throws Throwable { + public Object captureUrlTemplate(ProceedingJoinPoint joinPoint) throws Throwable { try { String urlTemplate = (String) joinPoint.getArgs()[0]; RestTemplateUrlTemplateHolder.setRestTemplateUrlTemplate(urlTemplate); From 89cb5573d9ff3f2ef5006f2dbeab596c1d5e3a5d Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 30 Jun 2017 17:33:57 -0600 Subject: [PATCH 2/4] =?UTF-8?q?bump=20commons=20to=201.3.0=CB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 135a3658..2b38982c 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ ${basedir} 4.0.27.Final 2.7.3 - 1.2.3.BUILD-SNAPSHOT + 1.3.0.BUILD-SNAPSHOT 1.4.0.BUILD-SNAPSHOT Ditmars.BUILD-SNAPSHOT From 8e11514e7c4063b9432c7625a98b2e2e76098461 Mon Sep 17 00:00:00 2001 From: Yongsung Yoon Date: Sat, 1 Jul 2017 09:03:52 +0900 Subject: [PATCH 3/4] Add options for RibbonCommand to use separate thread pools for hystrix (#2074) * Add options for RibbonCommand to use separate thread pools for hystrix * Remove lombok annotation and Add getter/setter for ZuulProperties$HystrixThreadPool * Add doc about how to configure hystrix thread pools in Zuul Developer Guide * Add testcases for HystrixThreadPoolKey of RibbonCommand * Tiny change about if block in AbstractRibbonCommand --- .../main/asciidoc/spring-cloud-netflix.adoc | 22 ++++ .../netflix/zuul/filters/ZuulProperties.java | 35 ++++++ .../route/support/AbstractRibbonCommand.java | 13 ++- .../zuul/filters/ZuulPropertiesTests.java | 6 + ...ibbonCommandHystrixThreadPoolKeyTests.java | 104 ++++++++++++++++++ 5 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonCommandHystrixThreadPoolKeyTests.java diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 3b0dd846..99a1bc65 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -886,6 +886,28 @@ ribbon: clients: client1, client2, client3 ---- +[[how-to-configure-hystrix-thread-pools]] +=== How to Configure Hystrix thread pools +If you change `zuul.ribbonIsolationStrategy` to THREAD, the thread isolation strategy for Hystrix will be used for all routes. In this case, the HystrixThreadPoolKey is set to "RibbonCommand" as default. It means that HystrixCommands for all routes will be executed in the same Hystrix thread pool. This behavior can be changed using the following configuration and it will result in HystrixCommands being executed in the Hystrix thread pool for each route. + +.application.yml +---- +zuul: + threadPool: + useSeparateThreadPools: true +---- + +The default HystrixThreadPoolKey in this case is same with service ID for each route. To add a prefix to HystrixThreadPoolKey, set `zuul.threadPool.threadPoolKeyPrefix` to a value that you want to add. For example: + +.application.yml +---- +zuul: + threadPool: + useSeparateThreadPools: true + threadPoolKeyPrefix: zuulgw +---- + + [[spring-cloud-feign]] == Declarative REST Client: Feign diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java index 8c2d40ad..0f1d3f34 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java @@ -160,6 +160,8 @@ public class ZuulProperties { private ExecutionIsolationStrategy ribbonIsolationStrategy = SEMAPHORE; private HystrixSemaphore semaphore = new HystrixSemaphore(); + + private HystrixThreadPool threadPool = new HystrixThreadPool(); public Set getIgnoredHeaders() { Set ignoredHeaders = new LinkedHashSet<>(this.ignoredHeaders); @@ -357,6 +359,39 @@ public class ZuulProperties { } + public static class HystrixThreadPool { + /** + * Flag to determine whether RibbonCommands should use separate thread pools for hystrix. + * By setting to true, RibbonCommands will be executed in a hystrix's thread pool that it is associated with. + * Each RibbonCommand will be associated with a thread pool according to its commandKey (serviceId). + * As default, all commands will be executed in a single thread pool whose threadPoolKey is "RibbonCommand". + * This property is only applicable when using THREAD as ribbonIsolationStrategy + */ + private boolean useSeparateThreadPools = false; + + /** + * A prefix for HystrixThreadPoolKey of hystrix's thread pool that is allocated to each service Id. + * This property is only applicable when using THREAD as ribbonIsolationStrategy and useSeparateThreadPools = true + */ + private String threadPoolKeyPrefix = ""; + + public boolean isUseSeparateThreadPools() { + return useSeparateThreadPools; + } + + public void setUseSeparateThreadPools(boolean useSeparateThreadPools) { + this.useSeparateThreadPools = useSeparateThreadPools; + } + + public String getThreadPoolKeyPrefix() { + return threadPoolKeyPrefix; + } + + public void setThreadPoolKeyPrefix(String threadPoolKeyPrefix) { + this.threadPoolKeyPrefix = threadPoolKeyPrefix; + } + } + public String getServletPattern() { String path = this.servletPath; if (!path.startsWith("/")) { diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/support/AbstractRibbonCommand.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/support/AbstractRibbonCommand.java index 3c157929..5431405e 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/support/AbstractRibbonCommand.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/support/AbstractRibbonCommand.java @@ -34,6 +34,7 @@ import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.HystrixCommandKey; import com.netflix.hystrix.HystrixCommandProperties; import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy; +import com.netflix.hystrix.HystrixThreadPoolKey; import com.netflix.zuul.constants.ZuulConstants; import com.netflix.zuul.context.RequestContext; @@ -78,6 +79,9 @@ public abstract class AbstractRibbonCommand Date: Thu, 6 Jul 2017 18:01:26 +0200 Subject: [PATCH 4/4] Use constant utility classes instead of constant interfaces (#2081) Signed-off-by: Gregor Zurowski --- .../netflix/hystrix/HystrixConstants.java | 8 +- .../zuul/filters/support/FilterConstants.java | 77 ++++++++++--------- .../eureka/EurekaClientConfigBean.java | 4 +- .../cloud/netflix/eureka/EurekaConstants.java | 8 +- .../eureka/server/EurekaServerConfigBean.java | 3 +- 5 files changed, 56 insertions(+), 44 deletions(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/HystrixConstants.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/HystrixConstants.java index 559dbf00..073eec02 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/HystrixConstants.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/HystrixConstants.java @@ -19,8 +19,12 @@ package org.springframework.cloud.netflix.hystrix; /** * @author Spencer Gibb */ -public interface HystrixConstants { +public class HystrixConstants { - String HYSTRIX_STREAM_DESTINATION = "springCloudHystrixStream"; + public static final String HYSTRIX_STREAM_DESTINATION = "springCloudHystrixStream"; + + private HystrixConstants() { + throw new AssertionError("Must not instantiate constant utility class"); + } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/support/FilterConstants.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/support/FilterConstants.java index 02b3fe3d..bf5f9c01 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/support/FilterConstants.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/support/FilterConstants.java @@ -26,190 +26,195 @@ import com.netflix.zuul.ZuulFilter; /** * @author Spencer Gibb */ -public interface FilterConstants { +public class FilterConstants { // KEY constants ----------------------------------- /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter} */ - String IS_DISPATCHER_SERVLET_REQUEST_KEY = "isDispatcherServletRequest"; + public static final String IS_DISPATCHER_SERVLET_REQUEST_KEY = "isDispatcherServletRequest"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter} */ - String FORWARD_TO_KEY = "forward.to"; + public static final String FORWARD_TO_KEY = "forward.to"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in TODO: determine use */ - String PROXY_KEY = "proxy"; + public static final String PROXY_KEY = "proxy"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter} */ - String REQUEST_ENTITY_KEY = "requestEntity"; + public static final String REQUEST_ENTITY_KEY = "requestEntity"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in to override the path of the request. */ - String REQUEST_URI_KEY = "requestURI"; + public static final String REQUEST_URI_KEY = "requestURI"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter} */ - String RETRYABLE_KEY = "retryable"; + public static final String RETRYABLE_KEY = "retryable"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter} */ - String ROUTING_DEBUG_KEY = "routingDebug"; + public static final String ROUTING_DEBUG_KEY = "routingDebug"; /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter} */ - String SERVICE_ID_KEY = "serviceId"; + public static final String SERVICE_ID_KEY = "serviceId"; // ORDER constants ----------------------------------- /** * Filter Order for {@link DebugFilter#filterOrder()} */ - int DEBUG_FILTER_ORDER = 1; + public static final int DEBUG_FILTER_ORDER = 1; /** * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter#filterOrder()} */ - int FORM_BODY_WRAPPER_FILTER_ORDER = -1; + public static final int FORM_BODY_WRAPPER_FILTER_ORDER = -1; /** * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter} */ - int PRE_DECORATION_FILTER_ORDER = 5; + public static final int PRE_DECORATION_FILTER_ORDER = 5; /** * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter#filterOrder()} */ - int RIBBON_ROUTING_FILTER_ORDER = 10; + public static final int RIBBON_ROUTING_FILTER_ORDER = 10; /** * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter#filterOrder()} */ - int SEND_ERROR_FILTER_ORDER = 0; + public static final int SEND_ERROR_FILTER_ORDER = 0; /** * Filter Order for {@link SendForwardFilter#filterOrder()} */ - int SEND_FORWARD_FILTER_ORDER = 500; + public static final int SEND_FORWARD_FILTER_ORDER = 500; /** * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter#filterOrder()} */ - int SEND_RESPONSE_FILTER_ORDER = 1000; + public static final int SEND_RESPONSE_FILTER_ORDER = 1000; /** * Filter Order for {@link org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter#filterOrder()} */ - int SIMPLE_HOST_ROUTING_FILTER_ORDER = 100; + public static final int SIMPLE_HOST_ROUTING_FILTER_ORDER = 100; /** * filter order for {@link Servlet30WrapperFilter#filterOrder()} */ - int SERVLET_30_WRAPPER_FILTER_ORDER = -2; + public static final int SERVLET_30_WRAPPER_FILTER_ORDER = -2; /** * filter order for {@link org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter#filterOrder()} */ - int SERVLET_DETECTION_FILTER_ORDER = -3; + public static final int SERVLET_DETECTION_FILTER_ORDER = -3; // Zuul Filter TYPE constants ----------------------------------- /** * {@link ZuulFilter#filterType()} error type. */ - String ERROR_TYPE = "error"; + public static final String ERROR_TYPE = "error"; /** * {@link ZuulFilter#filterType()} post type. */ - String POST_TYPE = "post"; + public static final String POST_TYPE = "post"; /** * {@link ZuulFilter#filterType()} pre type. */ - String PRE_TYPE = "pre"; + public static final String PRE_TYPE = "pre"; /** * {@link ZuulFilter#filterType()} route type. */ - String ROUTE_TYPE = "route"; + public static final String ROUTE_TYPE = "route"; // OTHER constants ----------------------------------- /** * Zuul {@link com.netflix.zuul.context.RequestContext} key for use in {@link org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter} */ - String FORWARD_LOCATION_PREFIX = "forward:"; + public static final String FORWARD_LOCATION_PREFIX = "forward:"; /** * default http port */ - int HTTP_PORT = 80; + public static final int HTTP_PORT = 80; /** * default https port */ - int HTTPS_PORT = 443; + public static final int HTTPS_PORT = 443; /** * http url scheme */ - String HTTP_SCHEME = "http"; + public static final String HTTP_SCHEME = "http"; /** * https url scheme */ - String HTTPS_SCHEME = "https"; + public static final String HTTPS_SCHEME = "https"; // HEADER constants ----------------------------------- /** * X-* Header for the matching url. Used when routes use a url rather than serviceId */ - String SERVICE_HEADER = "X-Zuul-Service"; + public static final String SERVICE_HEADER = "X-Zuul-Service"; /** * X-* Header for the matching serviceId */ - String SERVICE_ID_HEADER = "X-Zuul-ServiceId"; + public static final String SERVICE_ID_HEADER = "X-Zuul-ServiceId"; /** * X-Forwarded-For Header */ - String X_FORWARDED_FOR_HEADER = "X-Forwarded-For"; + public static final String X_FORWARDED_FOR_HEADER = "X-Forwarded-For"; /** * X-Forwarded-Host Header */ - String X_FORWARDED_HOST_HEADER = "X-Forwarded-Host"; + public static final String X_FORWARDED_HOST_HEADER = "X-Forwarded-Host"; /** * X-Forwarded-Prefix Header */ - String X_FORWARDED_PREFIX_HEADER = "X-Forwarded-Prefix"; + public static final String X_FORWARDED_PREFIX_HEADER = "X-Forwarded-Prefix"; /** * X-Forwarded-Port Header */ - String X_FORWARDED_PORT_HEADER = "X-Forwarded-Port"; + public static final String X_FORWARDED_PORT_HEADER = "X-Forwarded-Port"; /** * X-Forwarded-Proto Header */ - String X_FORWARDED_PROTO_HEADER = "X-Forwarded-Proto"; + public static final String X_FORWARDED_PROTO_HEADER = "X-Forwarded-Proto"; /** * X-Zuul-Debug Header */ - String X_ZUUL_DEBUG_HEADER = "X-Zuul-Debug-Header"; + public static final String X_ZUUL_DEBUG_HEADER = "X-Zuul-Debug-Header"; + + private FilterConstants() { + throw new AssertionError("Must not instantiate constant utility class"); + } + } diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java index a7f7228c..bc369a24 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java @@ -38,14 +38,14 @@ import lombok.Data; */ @Data @ConfigurationProperties(EurekaClientConfigBean.PREFIX) -public class EurekaClientConfigBean implements EurekaClientConfig, EurekaConstants { +public class EurekaClientConfigBean implements EurekaClientConfig { public static final String PREFIX = "eureka.client"; @Autowired(required = false) PropertyResolver propertyResolver; - public static final String DEFAULT_URL = "http://localhost:8761" + DEFAULT_PREFIX + public static final String DEFAULT_URL = "http://localhost:8761" + EurekaConstants.DEFAULT_PREFIX + "/"; public static final String DEFAULT_ZONE = "defaultZone"; diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaConstants.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaConstants.java index 75dc0493..1f24480a 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaConstants.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaConstants.java @@ -19,8 +19,12 @@ package org.springframework.cloud.netflix.eureka; /** * @author Spencer Gibb */ -public interface EurekaConstants { +public class EurekaConstants { - String DEFAULT_PREFIX = "/eureka"; + public static final String DEFAULT_PREFIX = "/eureka"; + + private EurekaConstants() { + throw new AssertionError("Must not instantiate constant utility class"); + } } diff --git a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfigBean.java b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfigBean.java index 26ffb67d..b4532e5a 100644 --- a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfigBean.java +++ b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfigBean.java @@ -23,7 +23,6 @@ import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.netflix.eureka.EurekaConstants; import org.springframework.core.env.PropertyResolver; import com.netflix.eureka.EurekaServerConfig; @@ -36,7 +35,7 @@ import lombok.Data; */ @Data @ConfigurationProperties(EurekaServerConfigBean.PREFIX) -public class EurekaServerConfigBean implements EurekaServerConfig, EurekaConstants { +public class EurekaServerConfigBean implements EurekaServerConfig { public static final String PREFIX = "eureka.server";