diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixTimerThreadPoolProperties.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixTimerThreadPoolProperties.java new file mode 100644 index 000000000..bb8aece1c --- /dev/null +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixTimerThreadPoolProperties.java @@ -0,0 +1,79 @@ +package com.netflix.hystrix; + +import com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty; +import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; +import com.netflix.hystrix.strategy.properties.HystrixProperty; + +import static com.netflix.hystrix.strategy.properties.HystrixProperty.Factory.asProperty; + +/** + * Properties for Hystrix timer thread pool. + *

+ * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius) + */ +public abstract class HystrixTimerThreadPoolProperties { + + private final HystrixProperty corePoolSize; + + protected HystrixTimerThreadPoolProperties() { + this(new Setter().withCoreSize(Runtime.getRuntime().availableProcessors())); + } + + protected HystrixTimerThreadPoolProperties(Setter setter) { + this.corePoolSize = getProperty("hystrix", "coreSize", setter.getCoreSize()); + } + + private static HystrixProperty getProperty(String propertyPrefix, String instanceProperty, Integer defaultValue) { + return asProperty(new HystrixPropertiesChainedArchaiusProperty.IntegerProperty( + new HystrixPropertiesChainedArchaiusProperty.DynamicIntegerProperty(propertyPrefix + ".timer.threadpool.default." + instanceProperty, defaultValue))); + } + + public HystrixProperty getCorePoolSize() { + return corePoolSize; + } + + /** + * Factory method to retrieve the default Setter. + */ + public static Setter Setter() { + return new Setter(); + } + + /** + * Fluent interface that allows chained setting of properties. + *

+ * See {@link HystrixPropertiesStrategy} for more information on order of precedence. + *

+ * Example: + *

+ *

 {@code
+     * HystrixTimerThreadPoolProperties.Setter()
+     *           .withCoreSize(10);
+     * } 
+ * + * @NotThreadSafe + */ + public static class Setter { + private Integer coreSize = null; + + private Setter() { + } + + public Integer getCoreSize() { + return coreSize; + } + + public Setter withCoreSize(int value) { + this.coreSize = value; + return this; + } + + /** + * Base properties for unit testing. + */ + /* package */ + static Setter getUnitTestPropertiesBuilder() { + return new Setter().withCoreSize(10); // size of thread pool + } + } +} diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.java b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.java index 4d496e3ec..8e6dfea07 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.java @@ -24,6 +24,7 @@ import com.netflix.hystrix.HystrixThreadPool; import com.netflix.hystrix.HystrixThreadPoolKey; import com.netflix.hystrix.HystrixThreadPoolProperties; +import com.netflix.hystrix.HystrixTimerThreadPoolProperties; import com.netflix.hystrix.strategy.HystrixPlugins; /** @@ -149,4 +150,17 @@ public HystrixCollapserProperties getCollapserProperties(HystrixCollapserKey col public String getCollapserPropertiesCacheKey(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) { return collapserKey.name(); } + + /** + * Construct an implementation of {@link com.netflix.hystrix.HystrixTimerThreadPoolProperties} for configuration of the timer thread pool + * that handles timeouts and collapser logic. + *

+ * Constructs instance of {@link HystrixPropertiesTimerThreadPoolDefault}. + * + * + * @return Implementation of {@link com.netflix.hystrix.HystrixTimerThreadPoolProperties} + */ + public HystrixTimerThreadPoolProperties getTimerThreadPoolProperties() { + return new HystrixPropertiesTimerThreadPoolDefault(); + } } diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesTimerThreadPoolDefault.java b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesTimerThreadPoolDefault.java new file mode 100644 index 000000000..e9a67bbf2 --- /dev/null +++ b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesTimerThreadPoolDefault.java @@ -0,0 +1,29 @@ +/** + * Copyright 2012 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.strategy.properties; + +import com.netflix.hystrix.HystrixThreadPoolKey; +import com.netflix.hystrix.HystrixThreadPoolProperties; +import com.netflix.hystrix.HystrixTimerThreadPoolProperties; + +/** + * Default implementation of {@link HystrixTimerThreadPoolProperties} using Archaius (https://github.com/Netflix/archaius) + * + * @ExcludeFromJavadoc + */ +public class HystrixPropertiesTimerThreadPoolDefault extends HystrixTimerThreadPoolProperties { + +} diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixTimer.java b/hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixTimer.java index a0fa1496e..123eea989 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixTimer.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixTimer.java @@ -24,6 +24,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import com.netflix.hystrix.strategy.HystrixPlugins; +import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -147,7 +149,11 @@ protected void startThreadIfNeeded() { * We want this only done once when created in compareAndSet so use an initialize method */ public void initialize() { - executor = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { + + HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy(); + int coreSize = propertiesStrategy.getTimerThreadPoolProperties().getCorePoolSize().get(); + + executor = new ScheduledThreadPoolExecutor(coreSize, new ThreadFactory() { final AtomicInteger counter = new AtomicInteger(); @Override diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixTimerTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixTimerTest.java index 9e5967083..09e6651f0 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixTimerTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixTimerTest.java @@ -1,12 +1,12 @@ /** * Copyright 2015 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. @@ -15,22 +15,35 @@ */ package com.netflix.hystrix.util; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import com.netflix.hystrix.Hystrix; +import com.netflix.hystrix.HystrixTimerThreadPoolProperties; +import com.netflix.hystrix.strategy.HystrixPlugins; +import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; +import com.netflix.hystrix.util.HystrixTimer.ScheduledExecutor; +import com.netflix.hystrix.util.HystrixTimer.TimerListener; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; import java.lang.ref.Reference; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; - -import com.netflix.hystrix.util.HystrixTimer.ScheduledExecutor; -import com.netflix.hystrix.util.HystrixTimer.TimerListener; +import static org.junit.Assert.*; public class HystrixTimerTest { + @Before + public void setUp() { + HystrixTimer timer = HystrixTimer.getInstance(); + HystrixTimer.reset(); + } + + @After + public void tearDown() { + HystrixPlugins.reset(); + } + @Test public void testSingleCommandSingleInterval() { HystrixTimer timer = HystrixTimer.getInstance(); @@ -163,6 +176,37 @@ public void testReset() { HystrixTimer.reset(); } + @Test + public void testThreadPoolSizeDefault() { + + HystrixTimer hystrixTimer = HystrixTimer.getInstance(); + hystrixTimer.startThreadIfNeeded(); + assertEquals(Runtime.getRuntime().availableProcessors(), hystrixTimer.executor.get().getThreadPool().getCorePoolSize()); + } + + @Test + public void testThreadPoolSizeConfiguredWithBuilder() { + + HystrixTimerThreadPoolProperties.Setter builder = HystrixTimerThreadPoolProperties.Setter().withCoreSize(1); + final HystrixTimerThreadPoolProperties props = new HystrixTimerThreadPoolProperties(builder) { + }; + + HystrixPropertiesStrategy strategy = new HystrixPropertiesStrategy() { + @Override + public HystrixTimerThreadPoolProperties getTimerThreadPoolProperties() { + return props; + } + }; + + HystrixPlugins.getInstance().registerPropertiesStrategy(strategy); + + HystrixTimer hystrixTimer = HystrixTimer.getInstance(); + hystrixTimer.startThreadIfNeeded(); + + assertEquals(1, hystrixTimer.executor.get().getThreadPool().getCorePoolSize()); + + } + private static class TestListener implements TimerListener { private final int interval; @@ -235,5 +279,5 @@ public int getIntervalTimeInMilliseconds() { } - + }