com.netflix.hystrix.HystrixThreadPoolProperties Maven / Gradle / Ivy
Show all versions of hystrix-core Show documentation
/**
* 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;
import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean;
import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import com.netflix.hystrix.util.HystrixRollingNumber;
/**
* 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.
*
* 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 */
static int default_coreSize = 10; // core size of thread pool
static int default_maximumSize = 10; // maximum size of thread pool
static int default_keepAliveTimeMinutes = 1; // minutes to keep a thread alive
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 it off and makes us use SynchronousQueue
static boolean default_allow_maximum_size_to_diverge_from_core_size = false; //should the maximumSize config value get read and used in configuring the threadPool
//turning this on should be a conscious decision by the user, so we default it to false
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;
private final HystrixProperty keepAliveTime;
private final HystrixProperty maxQueueSize;
private final HystrixProperty queueSizeRejectionThreshold;
private final boolean allowMaximumSizeToDivergeFromCoreSize;
private final HystrixProperty threadPoolRollingNumberStatisticalWindowInMilliseconds;
private final HystrixProperty threadPoolRollingNumberStatisticalWindowBuckets;
protected HystrixThreadPoolProperties(HystrixThreadPoolKey key) {
this(key, new Setter(), "hystrix");
}
protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder) {
this(key, builder, "hystrix");
}
protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder, String propertyPrefix) {
this.allowMaximumSizeToDivergeFromCoreSize = getValueOnce(propertyPrefix, key, "allowMaximumSizeToDivergeFromCoreSize",
builder.getAllowMaximumSizeToDivergeFromCoreSize(), default_allow_maximum_size_to_diverge_from_core_size);
this.corePoolSize = getProperty(propertyPrefix, key, "coreSize", builder.getCoreSize(), default_coreSize);
//this object always contains a reference to the configuration value for the maximumSize of the threadpool
//it only gets applied if allowMaximumSizeToDivergeFromCoreSize is true
this.maximumPoolSize = getProperty(propertyPrefix, key, "maximumSize", builder.getMaximumSize(), default_maximumSize);
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);
this.threadPoolRollingNumberStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingStats.timeInMilliseconds", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_threadPoolRollingNumberStatisticalWindow);
this.threadPoolRollingNumberStatisticalWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingStats.numBuckets", builder.getMetricsRollingStatisticalWindowBuckets(), default_threadPoolRollingNumberStatisticalWindowBuckets);
}
private static HystrixProperty getProperty(String propertyPrefix, HystrixThreadPoolKey key, String instanceProperty, Integer builderOverrideValue, Integer defaultValue) {
return forInteger()
.add(propertyPrefix + ".threadpool." + key.name() + "." + instanceProperty, builderOverrideValue)
.add(propertyPrefix + ".threadpool.default." + instanceProperty, defaultValue)
.build();
}
private static boolean getValueOnce(String propertyPrefix, HystrixThreadPoolKey key, String instanceProperty, boolean builderOverrideValue, boolean defaultValue) {
return forBoolean()
.add(propertyPrefix + ".threadpool." + key.name() + "." + instanceProperty, builderOverrideValue)
.add(propertyPrefix + ".threadpool.default." + instanceProperty, defaultValue)
.build()
.get();
}
/**
* Core thread-pool size that gets passed to {@link ThreadPoolExecutor#setCorePoolSize(int)}
*
* @return {@code HystrixProperty}
*/
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)}
*
* @return {@code HystrixProperty}
*/
public HystrixProperty keepAliveTimeMinutes() {
return keepAliveTime;
}
/**
* Max queue size that gets passed to {@link BlockingQueue} in {@link HystrixConcurrencyStrategy#getBlockingQueue(int)}
*
* This should only affect the instantiation of a threadpool - it is not eliglible to change a queue size on the fly.
* For that, use {@link #queueSizeRejectionThreshold()}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty maxQueueSize() {
return maxQueueSize;
}
/**
* Queue size rejection threshold is an artificial "max" size at which rejections will occur even if {@link #maxQueueSize} has not been reached. This is done because the {@link #maxQueueSize} of a
* {@link BlockingQueue} can not be dynamically changed and we want to support dynamically changing the queue size that affects rejections.
*
* This is used by {@link HystrixCommand} when queuing a thread for execution.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty queueSizeRejectionThreshold() {
return queueSizeRejectionThreshold;
}
public boolean getAllowMaximumSizeToDivergeFromCoreSize() {
return allowMaximumSizeToDivergeFromCoreSize;
}
/**
* Duration of statistical rolling window in milliseconds. This is passed into {@link HystrixRollingNumber} inside each {@link HystrixThreadPoolMetrics} instance.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingStatisticalWindowInMilliseconds() {
return threadPoolRollingNumberStatisticalWindowInMilliseconds;
}
/**
* Number of buckets the rolling statistical window is broken into. This is passed into {@link HystrixRollingNumber} inside each {@link HystrixThreadPoolMetrics} instance.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingStatisticalWindowBuckets() {
return threadPoolRollingNumberStatisticalWindowBuckets;
}
/**
* Factory method to retrieve the default Setter.
*/
public static Setter Setter() {
return new Setter();
}
/**
* Factory method to retrieve the default Setter.
* Groovy has a bug (GROOVY-6286) which does not allow method names and inner classes to have the same name
* This method fixes Issue #967 and allows Groovy consumers to choose this method and not trigger the bug
*/
public static Setter defaultSetter() {
return Setter();
}
/**
* Fluent interface that allows chained setting of properties that can be passed into a {@link HystrixThreadPool} via a {@link HystrixCommand} constructor to inject instance specific property
* overrides.
*
* See {@link HystrixPropertiesStrategy} for more information on order of precedence.
*
* Example:
*
*
{@code
* HystrixThreadPoolProperties.Setter()
* .withCoreSize(10)
* .withQueueSizeRejectionThreshold(10);
* }
*
* @NotThreadSafe
*/
public static class Setter {
private Integer coreSize = null;
private Integer maximumSize = null;
private Integer keepAliveTimeMinutes = null;
private Integer maxQueueSize = null;
private Integer queueSizeRejectionThreshold = null;
private boolean allowMaximumSizeToDivergeFromCoreSize = false;
private Integer rollingStatisticalWindowInMilliseconds = null;
private Integer rollingStatisticalWindowBuckets = null;
private Setter() {
}
public Integer getCoreSize() {
return coreSize;
}
public Integer getMaximumSize() {
return maximumSize;
}
public Integer getKeepAliveTimeMinutes() {
return keepAliveTimeMinutes;
}
public Integer getMaxQueueSize() {
return maxQueueSize;
}
public Integer getQueueSizeRejectionThreshold() {
return queueSizeRejectionThreshold;
}
public boolean getAllowMaximumSizeToDivergeFromCoreSize() {
return allowMaximumSizeToDivergeFromCoreSize;
}
public Integer getMetricsRollingStatisticalWindowInMilliseconds() {
return rollingStatisticalWindowInMilliseconds;
}
public Integer getMetricsRollingStatisticalWindowBuckets() {
return rollingStatisticalWindowBuckets;
}
public Setter withCoreSize(int value) {
this.coreSize = value;
return this;
}
public Setter withMaximumSize(int value) {
this.maximumSize = value;
return this;
}
public Setter withKeepAliveTimeMinutes(int value) {
this.keepAliveTimeMinutes = value;
return this;
}
public Setter withMaxQueueSize(int value) {
this.maxQueueSize = value;
return this;
}
public Setter withQueueSizeRejectionThreshold(int value) {
this.queueSizeRejectionThreshold = value;
return this;
}
public Setter withAllowMaximumSizeToDivergeFromCoreSize(boolean value) {
this.allowMaximumSizeToDivergeFromCoreSize = value;
return this;
}
public Setter withMetricsRollingStatisticalWindowInMilliseconds(int value) {
this.rollingStatisticalWindowInMilliseconds = value;
return this;
}
public Setter withMetricsRollingStatisticalWindowBuckets(int value) {
this.rollingStatisticalWindowBuckets = value;
return this;
}
}
}