From ef6b201b3552e2adc2c4547f35f95d4eefb26ff6 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Mon, 3 Oct 2016 11:38:36 -0700 Subject: [PATCH 1/5] Add configuration for Hystrix thread pool maximumSize --- .../hystrix/HystrixThreadPoolProperties.java | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java index 9b90ffd2b..a3ec7570c 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java @@ -15,9 +15,7 @@ */ package com.netflix.hystrix; -import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean; import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger; -import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forString; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -32,11 +30,19 @@ * Properties for instances of {@link HystrixThreadPool}. *

* Default implementation of methods uses Archaius (https://github.com/Netflix/archaius) + * + * Note a change in behavior in 1.5.7. Prior to that version, the configuration for 'coreSize' was used to control + * both coreSize and maximumSize. This is a fixed-size threadpool that can never give up an unused thread. In 1.5.7+, + * the values can diverge, and if you set coreSize < maximumSize, threads can be given up (subject to the keep-alive + * time) + * + * It is OK to leave maximumSize unset using any version of Hystrix. If you do, then maximum size will default to + * core size and you'll have a fixed-size threadpool. */ public abstract class HystrixThreadPoolProperties { /* defaults */ - private Integer default_coreSize = 10; // size of thread pool + private Integer default_coreSize = 10; // core size of thread pool private Integer default_keepAliveTimeMinutes = 1; // minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size) private Integer default_maxQueueSize = -1; // size of queue (this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject) // -1 turns if off and makes us use SynchronousQueue @@ -45,6 +51,7 @@ public abstract class HystrixThreadPoolProperties { private Integer default_threadPoolRollingNumberStatisticalWindowBuckets = 10; // number of buckets in rolling number (10 1-second buckets) private final HystrixProperty corePoolSize; + private final HystrixProperty maximumPoolSize; private final HystrixProperty keepAliveTime; private final HystrixProperty maxQueueSize; private final HystrixProperty queueSizeRejectionThreshold; @@ -61,6 +68,8 @@ protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder) protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder, String propertyPrefix) { this.corePoolSize = getProperty(propertyPrefix, key, "coreSize", builder.getCoreSize(), default_coreSize); + //if maximum size is not explicitly set, then default it to the core size of that pool. + this.maximumPoolSize = getProperty(propertyPrefix, key, "maximumSize", builder.getMaximumSize(), builder.getCoreSize()); this.keepAliveTime = getProperty(propertyPrefix, key, "keepAliveTimeMinutes", builder.getKeepAliveTimeMinutes(), default_keepAliveTimeMinutes); this.maxQueueSize = getProperty(propertyPrefix, key, "maxQueueSize", builder.getMaxQueueSize(), default_maxQueueSize); this.queueSizeRejectionThreshold = getProperty(propertyPrefix, key, "queueSizeRejectionThreshold", builder.getQueueSizeRejectionThreshold(), default_queueSizeRejectionThreshold); @@ -84,6 +93,15 @@ public HystrixProperty coreSize() { return corePoolSize; } + /** + * Maximum thread-pool size that gets passed to {@link ThreadPoolExecutor#setMaximumPoolSize(int)} + * + * @return {@code HystrixProperty} + */ + public HystrixProperty maximumSize() { + return maximumPoolSize; + } + /** * Keep-alive time in minutes that gets passed to {@link ThreadPoolExecutor#setKeepAliveTime(long, TimeUnit)} * @@ -169,6 +187,7 @@ public static Setter defaultSetter() { */ public static class Setter { private Integer coreSize = null; + private Integer maximumSize = null; private Integer keepAliveTimeMinutes = null; private Integer maxQueueSize = null; private Integer queueSizeRejectionThreshold = null; @@ -182,6 +201,10 @@ public Integer getCoreSize() { return coreSize; } + public Integer getMaximumSize() { + return maximumSize; + } + public Integer getKeepAliveTimeMinutes() { return keepAliveTimeMinutes; } @@ -207,6 +230,11 @@ public Setter withCoreSize(int value) { return this; } + public Setter withMaximumSize(int value) { + this.maximumSize = value; + return this; + } + public Setter withKeepAliveTimeMinutes(int value) { this.keepAliveTimeMinutes = value; return this; @@ -237,7 +265,8 @@ public Setter withMetricsRollingStatisticalWindowBuckets(int value) { */ /* package */static Setter getUnitTestPropertiesBuilder() { return new Setter() - .withCoreSize(10)// size of thread pool + .withCoreSize(10)// core size of thread pool + .withMaximumSize(15) //maximum size of thread pool .withKeepAliveTimeMinutes(1)// minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size) .withMaxQueueSize(100)// size of queue (but we never allow it to grow this big ... this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject) .withQueueSizeRejectionThreshold(10)// number of items in queue at which point we reject (this can be dyamically changed) @@ -260,6 +289,11 @@ public HystrixProperty coreSize() { return HystrixProperty.Factory.asProperty(builder.coreSize); } + @Override + public HystrixProperty maximumSize() { + return HystrixProperty.Factory.asProperty(builder.maximumSize); + } + @Override public HystrixProperty keepAliveTimeMinutes() { return HystrixProperty.Factory.asProperty(builder.keepAliveTimeMinutes); From c21d586661aa0b246f933eea695737d12a87b4c2 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 4 Oct 2016 13:33:08 -0700 Subject: [PATCH 2/5] Allow maximum size to affect HystrixThreadPool --- .../netflix/hystrix/HystrixThreadPool.java | 18 +- .../hystrix/HystrixThreadPoolProperties.java | 88 ++------ .../hystrix/AbstractTestHystrixCommand.java | 4 +- .../hystrix/HystrixObservableCommandTest.java | 2 +- .../HystrixThreadPoolPropertiesTest.java | 192 ++++++++++++++++++ .../hystrix/HystrixThreadPoolTest.java | 10 +- .../netflix/hystrix/InspectableBuilder.java | 2 +- 7 files changed, 233 insertions(+), 83 deletions(-) create mode 100644 hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolPropertiesTest.java diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPool.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPool.java index 51332d21e..6e59bf57f 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPool.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPool.java @@ -20,6 +20,8 @@ import com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler; import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory; import com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import rx.Scheduler; import rx.functions.Func0; @@ -158,6 +160,8 @@ public interface HystrixThreadPool { * @ThreadSafe */ /* package */static class HystrixThreadPoolDefault implements HystrixThreadPool { + private static final Logger logger = LoggerFactory.getLogger(HystrixThreadPoolDefault.class); + private final HystrixThreadPoolProperties properties; private final BlockingQueue queue; private final ThreadPoolExecutor threadPool; @@ -171,7 +175,7 @@ public HystrixThreadPoolDefault(HystrixThreadPoolKey threadPoolKey, HystrixThrea this.queue = concurrencyStrategy.getBlockingQueue(queueSize); this.metrics = HystrixThreadPoolMetrics.getInstance( threadPoolKey, - concurrencyStrategy.getThreadPool(threadPoolKey, properties.coreSize(), properties.coreSize(), properties.keepAliveTimeMinutes(), TimeUnit.MINUTES, queue), + concurrencyStrategy.getThreadPool(threadPoolKey, properties.coreSize(), properties.maximumSize(), properties.keepAliveTimeMinutes(), TimeUnit.MINUTES, queue), properties); this.threadPool = metrics.getThreadPool(); @@ -205,11 +209,19 @@ public Scheduler getScheduler(Func0 shouldInterruptThread) { // allow us to change things via fast-properties by setting it each time private void touchConfig() { final int dynamicCoreSize = properties.coreSize().get(); + int dynamicMaximumSize = properties.maximumSize().get(); + + if (dynamicMaximumSize < dynamicCoreSize) { + logger.error("Hystrix ThreadPool configuration for : " + metrics.getThreadPoolKey().name() + " is using coreSize = " + + dynamicCoreSize + " and maximumSize = " + dynamicMaximumSize + ". Maximum size will be set to " + + dynamicCoreSize + ", the coreSize value, since it must be equal to or greater than the coreSize value"); + dynamicMaximumSize = dynamicCoreSize; + } // In JDK 6, setCorePoolSize and setMaximumPoolSize will execute a lock operation. Avoid them if the pool size is not changed. - if (threadPool.getCorePoolSize() != dynamicCoreSize) { + if (threadPool.getCorePoolSize() != dynamicCoreSize || threadPool.getMaximumPoolSize() != dynamicMaximumSize) { threadPool.setCorePoolSize(dynamicCoreSize); - threadPool.setMaximumPoolSize(dynamicCoreSize); // we always want maxSize the same as coreSize, we are not using a dynamically resizing pool + threadPool.setMaximumPoolSize(dynamicMaximumSize); } threadPool.setKeepAliveTime(properties.keepAliveTimeMinutes().get(), TimeUnit.MINUTES); // this doesn't really matter since we're not resizing diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java index a3ec7570c..8a76eaba9 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java @@ -38,17 +38,22 @@ * * It is OK to leave maximumSize unset using any version of Hystrix. If you do, then maximum size will default to * core size and you'll have a fixed-size threadpool. + * + * If you accidentally set maximumSize < coreSize, then maximum will be raised to coreSize + * (this prioritizes keeping extra threads around rather than inducing threadpool rejections) */ public abstract class HystrixThreadPoolProperties { + + /* defaults */ - private Integer default_coreSize = 10; // core size of thread pool - private Integer default_keepAliveTimeMinutes = 1; // minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size) - private Integer default_maxQueueSize = -1; // size of queue (this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject) + static int default_coreSize = 10; // core size of thread pool + static int default_keepAliveTimeMinutes = 1; // minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size) + static int default_maxQueueSize = -1; // size of queue (this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject) // -1 turns if off and makes us use SynchronousQueue - private Integer default_queueSizeRejectionThreshold = 5; // number of items in queue - private Integer default_threadPoolRollingNumberStatisticalWindow = 10000; // milliseconds for rolling number - private Integer default_threadPoolRollingNumberStatisticalWindowBuckets = 10; // number of buckets in rolling number (10 1-second buckets) + static int default_queueSizeRejectionThreshold = 5; // number of items in queue + static int default_threadPoolRollingNumberStatisticalWindow = 10000; // milliseconds for rolling number + static int default_threadPoolRollingNumberStatisticalWindowBuckets = 10; // number of buckets in rolling number (10 1-second buckets) private final HystrixProperty corePoolSize; private final HystrixProperty maximumPoolSize; @@ -67,9 +72,13 @@ protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder) } protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder, String propertyPrefix) { + //we allow maximum pool size to be configured lower than core size here + //however, at runtime, if this configuration gets applied, we will always ensure that maximumSize >= coreSize this.corePoolSize = getProperty(propertyPrefix, key, "coreSize", builder.getCoreSize(), default_coreSize); - //if maximum size is not explicitly set, then default it to the core size of that pool. - this.maximumPoolSize = getProperty(propertyPrefix, key, "maximumSize", builder.getMaximumSize(), builder.getCoreSize()); + + //if left unset, maxiumumSize will default to coreSize + this.maximumPoolSize = getProperty(propertyPrefix, key, "maximumSize", builder.getMaximumSize(), corePoolSize.get()); + this.keepAliveTime = getProperty(propertyPrefix, key, "keepAliveTimeMinutes", builder.getKeepAliveTimeMinutes(), default_keepAliveTimeMinutes); this.maxQueueSize = getProperty(propertyPrefix, key, "maxQueueSize", builder.getMaxQueueSize(), default_maxQueueSize); this.queueSizeRejectionThreshold = getProperty(propertyPrefix, key, "queueSizeRejectionThreshold", builder.getQueueSizeRejectionThreshold(), default_queueSizeRejectionThreshold); @@ -260,71 +269,8 @@ public Setter withMetricsRollingStatisticalWindowBuckets(int value) { return this; } - /** - * Base properties for unit testing. - */ - /* package */static Setter getUnitTestPropertiesBuilder() { - return new Setter() - .withCoreSize(10)// core size of thread pool - .withMaximumSize(15) //maximum size of thread pool - .withKeepAliveTimeMinutes(1)// minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size) - .withMaxQueueSize(100)// size of queue (but we never allow it to grow this big ... this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject) - .withQueueSizeRejectionThreshold(10)// number of items in queue at which point we reject (this can be dyamically changed) - .withMetricsRollingStatisticalWindowInMilliseconds(10000)// milliseconds for rolling number - .withMetricsRollingStatisticalWindowBuckets(10);// number of buckets in rolling number (10 1-second buckets) - } - /** - * Return a static representation of the properties with values from the Builder so that UnitTests can create properties that are not affected by the actual implementations which pick up their - * values dynamically. - * - * @param builder builder for a {@link HystrixThreadPoolProperties} - * @return HystrixThreadPoolProperties - */ - /* package */static HystrixThreadPoolProperties asMock(final Setter builder) { - return new HystrixThreadPoolProperties(TestThreadPoolKey.TEST) { - - @Override - public HystrixProperty coreSize() { - return HystrixProperty.Factory.asProperty(builder.coreSize); - } - - @Override - public HystrixProperty maximumSize() { - return HystrixProperty.Factory.asProperty(builder.maximumSize); - } - - @Override - public HystrixProperty keepAliveTimeMinutes() { - return HystrixProperty.Factory.asProperty(builder.keepAliveTimeMinutes); - } - - @Override - public HystrixProperty maxQueueSize() { - return HystrixProperty.Factory.asProperty(builder.maxQueueSize); - } - - @Override - public HystrixProperty queueSizeRejectionThreshold() { - return HystrixProperty.Factory.asProperty(builder.queueSizeRejectionThreshold); - } - - @Override - public HystrixProperty metricsRollingStatisticalWindowInMilliseconds() { - return HystrixProperty.Factory.asProperty(builder.rollingStatisticalWindowInMilliseconds); - } - - @Override - public HystrixProperty metricsRollingStatisticalWindowBuckets() { - return HystrixProperty.Factory.asProperty(builder.rollingStatisticalWindowBuckets); - } - - }; - } - private static enum TestThreadPoolKey implements HystrixThreadPoolKey { - TEST - } } } diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/AbstractTestHystrixCommand.java b/hystrix-core/src/test/java/com/netflix/hystrix/AbstractTestHystrixCommand.java index 64b4d071a..2a2204681 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/AbstractTestHystrixCommand.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/AbstractTestHystrixCommand.java @@ -46,9 +46,9 @@ public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKe @Override public HystrixThreadPoolProperties getThreadPoolProperties(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) { if (builder == null) { - builder = HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder(); + builder = HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder(); } - return HystrixThreadPoolProperties.Setter.asMock(builder); + return HystrixThreadPoolPropertiesTest.asMock(builder); } @Override diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java index d129f2e47..c1e118169 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java @@ -5335,7 +5335,7 @@ private static class TestThreadIsolationWithSemaphoreSetSmallCommand extends Tes private TestThreadIsolationWithSemaphoreSetSmallCommand(TestCircuitBreaker circuitBreaker, int poolSize, Action0 action) { super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) .setThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(TestThreadIsolationWithSemaphoreSetSmallCommand.class.getSimpleName())) - .setThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder() + .setThreadPoolPropertiesDefaults(HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder() .withCoreSize(poolSize).withMaxQueueSize(0)) .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolPropertiesTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolPropertiesTest.java new file mode 100644 index 000000000..5fc6dc63a --- /dev/null +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolPropertiesTest.java @@ -0,0 +1,192 @@ +/** + * Copyright 2016 Netflix, Inc. + * + * 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 com.netflix.hystrix; + +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.Test; + +import com.netflix.config.ConfigurationManager; +import com.netflix.hystrix.strategy.properties.HystrixProperty; + +public class HystrixThreadPoolPropertiesTest { + + /** + * Base properties for unit testing. + */ + /* package */static HystrixThreadPoolProperties.Setter getUnitTestPropertiesBuilder() { + return HystrixThreadPoolProperties.Setter() + .withCoreSize(10)// core size of thread pool + .withMaximumSize(15) //maximum size of thread pool + .withKeepAliveTimeMinutes(1)// minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size) + .withMaxQueueSize(100)// size of queue (but we never allow it to grow this big ... this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject) + .withQueueSizeRejectionThreshold(10)// number of items in queue at which point we reject (this can be dyamically changed) + .withMetricsRollingStatisticalWindowInMilliseconds(10000)// milliseconds for rolling number + .withMetricsRollingStatisticalWindowBuckets(10);// number of buckets in rolling number (10 1-second buckets) + } + + /** + * Return a static representation of the properties with values from the Builder so that UnitTests can create properties that are not affected by the actual implementations which pick up their + * values dynamically. + * + * @param builder builder for a {@link HystrixThreadPoolProperties} + * @return HystrixThreadPoolProperties + */ + /* package */static HystrixThreadPoolProperties asMock(final HystrixThreadPoolProperties.Setter builder) { + return new HystrixThreadPoolProperties(TestThreadPoolKey.TEST) { + + @Override + public HystrixProperty coreSize() { + return HystrixProperty.Factory.asProperty(builder.getCoreSize()); + } + + @Override + public HystrixProperty maximumSize() { + return HystrixProperty.Factory.asProperty(builder.getMaximumSize()); + } + + @Override + public HystrixProperty keepAliveTimeMinutes() { + return HystrixProperty.Factory.asProperty(builder.getKeepAliveTimeMinutes()); + } + + @Override + public HystrixProperty maxQueueSize() { + return HystrixProperty.Factory.asProperty(builder.getMaxQueueSize()); + } + + @Override + public HystrixProperty queueSizeRejectionThreshold() { + return HystrixProperty.Factory.asProperty(builder.getQueueSizeRejectionThreshold()); + } + + @Override + public HystrixProperty metricsRollingStatisticalWindowInMilliseconds() { + return HystrixProperty.Factory.asProperty(builder.getMetricsRollingStatisticalWindowInMilliseconds()); + } + + @Override + public HystrixProperty metricsRollingStatisticalWindowBuckets() { + return HystrixProperty.Factory.asProperty(builder.getMetricsRollingStatisticalWindowBuckets()); + } + + }; + + } + + private static enum TestThreadPoolKey implements HystrixThreadPoolKey { + TEST + } + + @After + public void cleanup() { + ConfigurationManager.getConfigInstance().clear(); + } + + @Test + public void testSetNeitherCoreNorMaximumSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, HystrixThreadPoolProperties.Setter()) { + + }; + + assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue()); + assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetCoreSizeOnly() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter().withCoreSize(14)) { + + }; + + assertEquals(14, properties.coreSize().get().intValue()); + assertEquals(14, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetMaximumSizeOnlyLowerThanDefaultCoreSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter().withMaximumSize(3)) { + + }; + + assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue()); + assertEquals(3, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetMaximumSizeOnlyEqualToDefaultCoreSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter().withMaximumSize(HystrixThreadPoolProperties.default_coreSize)) { + + }; + + assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue()); + assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetMaximumSizeOnlyGreaterThanDefaultCoreSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter().withMaximumSize(21)) { + + }; + + assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue()); + assertEquals(21, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetCoreSizeLessThanMaximumSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter() + .withCoreSize(2) + .withMaximumSize(8)) { + + }; + + assertEquals(2, properties.coreSize().get().intValue()); + assertEquals(8, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetCoreSizeEqualToMaximumSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter() + .withCoreSize(7) + .withMaximumSize(7)) { + + }; + + assertEquals(7, properties.coreSize().get().intValue()); + assertEquals(7, properties.maximumSize().get().intValue()); + } + + @Test + public void testSetCoreSizeGreaterThanMaximumSize() { + HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST, + HystrixThreadPoolProperties.Setter() + .withCoreSize(12) + .withMaximumSize(8)) { + + }; + + assertEquals(12, properties.coreSize().get().intValue()); + assertEquals(8, properties.maximumSize().get().intValue()); + } +} diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolTest.java index 64f6f714a..c8cf60455 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolTest.java @@ -49,7 +49,7 @@ public void testShutdown() { int count = Factory.threadPools.size(); HystrixThreadPool pool = Factory.getInstance(HystrixThreadPoolKey.Factory.asKey("threadPoolFactoryTest"), - HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder()); + HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder()); assertEquals(count + 1, Factory.threadPools.size()); assertFalse(pool.getExecutor().isShutdown()); @@ -67,7 +67,7 @@ public void testShutdownWithWait() { int count = Factory.threadPools.size(); HystrixThreadPool pool = Factory.getInstance(HystrixThreadPoolKey.Factory.asKey("threadPoolFactoryTest"), - HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder()); + HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder()); assertEquals(count + 1, Factory.threadPools.size()); assertFalse(pool.getExecutor().isShutdown()); @@ -105,9 +105,9 @@ public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(Hystri }); HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("threadPoolFactoryConcurrencyTest"); HystrixThreadPool poolOne = new HystrixThreadPool.HystrixThreadPoolDefault( - threadPoolKey, HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder()); + threadPoolKey, HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder()); HystrixThreadPool poolTwo = new HystrixThreadPool.HystrixThreadPoolDefault( - threadPoolKey, HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder()); + threadPoolKey, HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder()); assertThat(poolOne.getExecutor(), is(poolTwo.getExecutor())); //Now that we get the threadPool from the metrics object, this will always be equal HystrixMetricsPublisherThreadPoolContainer hystrixMetricsPublisherThreadPool = @@ -126,7 +126,7 @@ public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(Hystri public void testUnsubscribeHystrixThreadPool() throws InterruptedException { // methods are package-private so can't test it somewhere else HystrixThreadPool pool = Factory.getInstance(HystrixThreadPoolKey.Factory.asKey("threadPoolFactoryTest"), - HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder()); + HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder()); final AtomicBoolean interrupted = new AtomicBoolean(); final CountDownLatch start = new CountDownLatch(1); diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/InspectableBuilder.java b/hystrix-core/src/test/java/com/netflix/hystrix/InspectableBuilder.java index ad783b9cb..3d5ff9d56 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/InspectableBuilder.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/InspectableBuilder.java @@ -37,7 +37,7 @@ public static class TestCommandBuilder { HystrixCircuitBreaker circuitBreaker; HystrixThreadPool threadPool = null; HystrixCommandProperties.Setter commandPropertiesDefaults = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter(); - HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults = HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder(); + HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults = HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder(); HystrixCommandMetrics metrics; AbstractCommand.TryableSemaphore fallbackSemaphore = null; AbstractCommand.TryableSemaphore executionSemaphore = null; From 9d9f1ed0c214d7cc45465c823fbbae57d04f9ccf Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 4 Oct 2016 13:38:04 -0700 Subject: [PATCH 3/5] Add maximumSize to Hystrix Configuration stream --- .../hystrix/config/HystrixThreadPoolConfiguration.java | 9 ++++++++- .../hystrix/serial/SerialHystrixConfiguration.java | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixThreadPoolConfiguration.java b/hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixThreadPoolConfiguration.java index 321a838a3..ca19ed2a2 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixThreadPoolConfiguration.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixThreadPoolConfiguration.java @@ -23,17 +23,19 @@ public class HystrixThreadPoolConfiguration { private static final String VERSION = "1"; private final HystrixThreadPoolKey threadPoolKey; private final int coreSize; + private final int maximumSize; private final int maxQueueSize; private final int queueRejectionThreshold; private final int keepAliveTimeInMinutes; private final int rollingCounterNumberOfBuckets; private final int rollingCounterBucketSizeInMilliseconds; - public HystrixThreadPoolConfiguration(HystrixThreadPoolKey threadPoolKey, int coreSize, int maxQueueSize, int queueRejectionThreshold, + public HystrixThreadPoolConfiguration(HystrixThreadPoolKey threadPoolKey, int coreSize, int maximumSize, int maxQueueSize, int queueRejectionThreshold, int keepAliveTimeInMinutes, int rollingCounterNumberOfBuckets, int rollingCounterBucketSizeInMilliseconds) { this.threadPoolKey = threadPoolKey; this.coreSize = coreSize; + this.maximumSize = maximumSize; this.maxQueueSize = maxQueueSize; this.queueRejectionThreshold = queueRejectionThreshold; this.keepAliveTimeInMinutes = keepAliveTimeInMinutes; @@ -45,6 +47,7 @@ public static HystrixThreadPoolConfiguration sample(HystrixThreadPoolKey threadP return new HystrixThreadPoolConfiguration( threadPoolKey, threadPoolProperties.coreSize().get(), + threadPoolProperties.maximumSize().get(), threadPoolProperties.maxQueueSize().get(), threadPoolProperties.queueSizeRejectionThreshold().get(), threadPoolProperties.keepAliveTimeMinutes().get(), @@ -60,6 +63,10 @@ public int getCoreSize() { return coreSize; } + public int getMaximumSize() { + return maximumSize; + } + public int getMaxQueueSize() { return maxQueueSize; } diff --git a/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java b/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java index 417157f14..e3cbaae9a 100644 --- a/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java +++ b/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java @@ -252,6 +252,7 @@ private static void writeCommandConfigJson(JsonGenerator json, HystrixCommandKey private static void writeThreadPoolConfigJson(JsonGenerator json, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolConfiguration threadPoolConfig) throws IOException { json.writeObjectFieldStart(threadPoolKey.name()); json.writeNumberField("coreSize", threadPoolConfig.getCoreSize()); + json.writeNumberField("maximumSize", threadPoolConfig.getMaximumSize()); json.writeNumberField("maxQueueSize", threadPoolConfig.getMaxQueueSize()); json.writeNumberField("queueRejectionThreshold", threadPoolConfig.getQueueRejectionThreshold()); json.writeNumberField("keepAliveTimeInMinutes", threadPoolConfig.getKeepAliveTimeInMinutes()); From b42e36c028f44489b5d7f2b32cf672ab075065e0 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 4 Oct 2016 16:28:18 -0700 Subject: [PATCH 4/5] Add maximum size in configuration stream output --- .../contrib/sample/stream/HystrixConfigurationJsonStream.java | 1 + .../com/netflix/hystrix/serial/SerialHystrixConfiguration.java | 1 + 2 files changed, 2 insertions(+) diff --git a/hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigurationJsonStream.java b/hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigurationJsonStream.java index 1008fb970..57e983dfb 100644 --- a/hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigurationJsonStream.java +++ b/hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigurationJsonStream.java @@ -116,6 +116,7 @@ private static void writeCommandConfigJson(JsonGenerator json, HystrixCommandKey private static void writeThreadPoolConfigJson(JsonGenerator json, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolConfiguration threadPoolConfig) throws IOException { json.writeObjectFieldStart(threadPoolKey.name()); json.writeNumberField("coreSize", threadPoolConfig.getCoreSize()); + json.writeNumberField("maximumSize", threadPoolConfig.getMaximumSize()); json.writeNumberField("maxQueueSize", threadPoolConfig.getMaxQueueSize()); json.writeNumberField("queueRejectionThreshold", threadPoolConfig.getQueueRejectionThreshold()); json.writeNumberField("keepAliveTimeInMinutes", threadPoolConfig.getKeepAliveTimeInMinutes()); diff --git a/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java b/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java index e3cbaae9a..162bfc5e1 100644 --- a/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java +++ b/hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java @@ -177,6 +177,7 @@ public static HystrixConfiguration fromByteBuffer(ByteBuffer bb) { HystrixThreadPoolConfiguration threadPoolConfig = new HystrixThreadPoolConfiguration( threadPoolKey, threadPool.getValue().path("coreSize").asInt(), + threadPool.getValue().path("maximumSize").asInt(), threadPool.getValue().path("maxQueueSize").asInt(), threadPool.getValue().path("queueRejectionThreshold").asInt(), threadPool.getValue().path("keepAliveTimeInMinutes").asInt(), From c6fb4e1f896bda976a66bdfb7bc25bde1ff633a2 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 5 Oct 2016 12:47:58 -0700 Subject: [PATCH 5/5] Add maximumSize to unit test --- .../java/com/netflix/hystrix/HystrixObservableCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java index c1e118169..8b38bba4d 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java @@ -5336,7 +5336,7 @@ private TestThreadIsolationWithSemaphoreSetSmallCommand(TestCircuitBreaker circu super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) .setThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(TestThreadIsolationWithSemaphoreSetSmallCommand.class.getSimpleName())) .setThreadPoolPropertiesDefaults(HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder() - .withCoreSize(poolSize).withMaxQueueSize(0)) + .withCoreSize(poolSize).withMaximumSize(poolSize).withMaxQueueSize(0)) .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) .withExecutionIsolationSemaphoreMaxConcurrentRequests(1)));