-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
HystrixThreadPoolProperties.java
304 lines (257 loc) · 13.1 KB
/
HystrixThreadPoolProperties.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/**
* 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}.
* <p>
* 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 if 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<Integer> corePoolSize;
private final HystrixProperty<Integer> maximumPoolSize;
private final HystrixProperty<Integer> keepAliveTime;
private final HystrixProperty<Integer> maxQueueSize;
private final HystrixProperty<Integer> queueSizeRejectionThreshold;
private final boolean allowMaximumSizeToDivergeFromCoreSize;
private final HystrixProperty<Integer> threadPoolRollingNumberStatisticalWindowInMilliseconds;
private final HystrixProperty<Integer> 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 .threadpool
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<Integer> 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<Integer>}
*/
public HystrixProperty<Integer> coreSize() {
return corePoolSize;
}
/**
* Maximum thread-pool size that gets passed to {@link ThreadPoolExecutor#setMaximumPoolSize(int)}
*
* @return {@code HystrixProperty<Integer>}
*/
public HystrixProperty<Integer> maximumSize() {
return maximumPoolSize;
}
/**
* Keep-alive time in minutes that gets passed to {@link ThreadPoolExecutor#setKeepAliveTime(long, TimeUnit)}
*
* @return {@code HystrixProperty<Integer>}
*/
public HystrixProperty<Integer> 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<Integer>}
*/
public HystrixProperty<Integer> 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.
* <p>
* This is used by {@link HystrixCommand} when queuing a thread for execution.
*
* @return {@code HystrixProperty<Integer>}
*/
public HystrixProperty<Integer> 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<Integer>}
*/
public HystrixProperty<Integer> 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<Integer>}
*/
public HystrixProperty<Integer> 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.
* <p>
* See {@link HystrixPropertiesStrategy} for more information on order of precedence.
* <p>
* Example:
* <p>
* <pre> {@code
* HystrixThreadPoolProperties.Setter()
* .withCoreSize(10)
* .withQueueSizeRejectionThreshold(10);
* } </pre>
*
* @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;
}
}
}