Merge remote-tracking branch 'Upstream/master' into http-client-centralization
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -160,6 +160,8 @@ public class ZuulProperties {
|
||||
private ExecutionIsolationStrategy ribbonIsolationStrategy = SEMAPHORE;
|
||||
|
||||
private HystrixSemaphore semaphore = new HystrixSemaphore();
|
||||
|
||||
private HystrixThreadPool threadPool = new HystrixThreadPool();
|
||||
|
||||
public Set<String> getIgnoredHeaders() {
|
||||
Set<String> 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("/")) {
|
||||
|
||||
@@ -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<LBC extends AbstractLoadBalancerAwar
|
||||
ZuulProperties zuulProperties) {
|
||||
|
||||
// @formatter:off
|
||||
Setter commandSetter = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RibbonCommand"))
|
||||
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
|
||||
|
||||
final HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
|
||||
.withExecutionIsolationStrategy(zuulProperties.getRibbonIsolationStrategy());
|
||||
if (zuulProperties.getRibbonIsolationStrategy() == ExecutionIsolationStrategy.SEMAPHORE){
|
||||
@@ -87,13 +91,12 @@ public abstract class AbstractRibbonCommand<LBC extends AbstractLoadBalancerAwar
|
||||
final DynamicIntProperty value = DynamicPropertyFactory.getInstance()
|
||||
.getIntProperty(name, zuulProperties.getSemaphore().getMaxSemaphores());
|
||||
setter.withExecutionIsolationSemaphoreMaxConcurrentRequests(value.get());
|
||||
} else {
|
||||
// TODO Find out is some parameters can be set here
|
||||
} else if (zuulProperties.getThreadPool().isUseSeparateThreadPools()) {
|
||||
final String threadPoolKey = zuulProperties.getThreadPool().getThreadPoolKeyPrefix() + commandKey;
|
||||
commandSetter.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey));
|
||||
}
|
||||
|
||||
return Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RibbonCommand"))
|
||||
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
|
||||
.andCommandPropertiesDefaults(setter);
|
||||
return commandSetter.andCommandPropertiesDefaults(setter);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -103,4 +104,9 @@ public class ZuulPropertiesTests {
|
||||
assertFalse(this.zuul.getSensitiveHeaders().contains("Cookie"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultHystrixThreadPool() {
|
||||
assertFalse(this.zuul.getThreadPool().isUseSeparateThreadPools());
|
||||
assertEquals("", this.zuul.getThreadPool().getThreadPoolKeyPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.zuul.filters.route.support;
|
||||
|
||||
import com.netflix.client.ClientRequest;
|
||||
import com.netflix.hystrix.HystrixCommandProperties;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Yongsung Yoon
|
||||
*/
|
||||
public class RibbonCommandHystrixThreadPoolKeyTests {
|
||||
|
||||
private ZuulProperties zuulProperties;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
zuulProperties = new ZuulProperties();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultHystrixThreadPoolKey() throws Exception {
|
||||
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
|
||||
|
||||
TestRibbonCommand ribbonCommand1 = new TestRibbonCommand("testCommand1", zuulProperties);
|
||||
TestRibbonCommand ribbonCommand2 = new TestRibbonCommand("testCommand2", zuulProperties);
|
||||
|
||||
// CommandGroupKey should be used as ThreadPoolKey as default.
|
||||
assertThat(ribbonCommand1.getThreadPoolKey().name()).isEqualTo(ribbonCommand1.getCommandGroup().name());
|
||||
assertThat(ribbonCommand2.getThreadPoolKey().name()).isEqualTo(ribbonCommand2.getCommandGroup().name());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseSeparateThreadPools() throws Exception {
|
||||
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
|
||||
zuulProperties.getThreadPool().setUseSeparateThreadPools(true);
|
||||
|
||||
TestRibbonCommand ribbonCommand1 = new TestRibbonCommand("testCommand1", zuulProperties);
|
||||
TestRibbonCommand ribbonCommand2 = new TestRibbonCommand("testCommand2", zuulProperties);
|
||||
|
||||
assertThat(ribbonCommand1.getThreadPoolKey().name()).isEqualTo("testCommand1");
|
||||
assertThat(ribbonCommand2.getThreadPoolKey().name()).isEqualTo("testCommand2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadPoolKeyPrefix() throws Exception {
|
||||
final String prefix = "zuulgw-";
|
||||
|
||||
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
|
||||
zuulProperties.getThreadPool().setUseSeparateThreadPools(true);
|
||||
zuulProperties.getThreadPool().setThreadPoolKeyPrefix(prefix);
|
||||
|
||||
TestRibbonCommand ribbonCommand1 = new TestRibbonCommand("testCommand1", zuulProperties);
|
||||
TestRibbonCommand ribbonCommand2 = new TestRibbonCommand("testCommand2", zuulProperties);
|
||||
|
||||
assertThat(ribbonCommand1.getThreadPoolKey().name()).isEqualTo(prefix + "testCommand1");
|
||||
assertThat(ribbonCommand2.getThreadPoolKey().name()).isEqualTo(prefix + "testCommand2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSideEffectOnSemaphoreIsolation() throws Exception {
|
||||
final String prefix = "zuulgw-";
|
||||
|
||||
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);
|
||||
zuulProperties.getThreadPool().setUseSeparateThreadPools(true);
|
||||
zuulProperties.getThreadPool().setThreadPoolKeyPrefix(prefix);
|
||||
|
||||
TestRibbonCommand ribbonCommand1 = new TestRibbonCommand("testCommand1", zuulProperties);
|
||||
TestRibbonCommand ribbonCommand2 = new TestRibbonCommand("testCommand2", zuulProperties);
|
||||
|
||||
// There should be no side effect on semaphore isolation
|
||||
assertThat(ribbonCommand1.getThreadPoolKey().name()).isEqualTo(ribbonCommand1.getCommandGroup().name());
|
||||
assertThat(ribbonCommand2.getThreadPoolKey().name()).isEqualTo(ribbonCommand2.getCommandGroup().name());
|
||||
}
|
||||
|
||||
public static class TestRibbonCommand extends AbstractRibbonCommand {
|
||||
public TestRibbonCommand(String commandKey, ZuulProperties zuulProperties) {
|
||||
super(commandKey, null, null, zuulProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClientRequest createRequest() throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user