001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.model;
018
019import java.util.concurrent.BlockingQueue;
020import java.util.concurrent.Future;
021import java.util.concurrent.ThreadPoolExecutor;
022import java.util.concurrent.TimeUnit;
023
024import javax.xml.bind.annotation.XmlAccessType;
025import javax.xml.bind.annotation.XmlAccessorType;
026import javax.xml.bind.annotation.XmlAttribute;
027
028import org.apache.camel.spi.Metadata;
029
030@XmlAccessorType(XmlAccessType.FIELD)
031public class HystrixConfigurationCommon extends IdentifiedType {
032
033    @XmlAttribute @Metadata(defaultValue = "CamelHystrix")
034    private String groupKey;
035    @XmlAttribute @Metadata(defaultValue = "CamelHystrix")
036    private String threadPoolKey;
037    @XmlAttribute
038    @Metadata(label = "command", defaultValue = "true")
039    private Boolean circuitBreakerEnabled;
040    @XmlAttribute
041    @Metadata(label = "command", defaultValue = "50")
042    private Integer circuitBreakerErrorThresholdPercentage;
043    @XmlAttribute
044    @Metadata(label = "command", defaultValue = "false")
045    private Boolean circuitBreakerForceClosed;
046    @XmlAttribute
047    @Metadata(label = "command", defaultValue = "false")
048    private Boolean circuitBreakerForceOpen;
049    @XmlAttribute
050    @Metadata(label = "command", defaultValue = "20")
051    private Integer circuitBreakerRequestVolumeThreshold;
052    @XmlAttribute
053    @Metadata(label = "command", defaultValue = "5000")
054    private Integer circuitBreakerSleepWindowInMilliseconds;
055    @XmlAttribute
056    @Metadata(label = "command", defaultValue = "20")
057    private Integer executionIsolationSemaphoreMaxConcurrentRequests;
058    @XmlAttribute
059    @Metadata(label = "command", defaultValue = "THREAD", enums = "THREAD,SEMAPHORE")
060    private String executionIsolationStrategy;
061    @XmlAttribute
062    @Metadata(label = "command", defaultValue = "true")
063    private Boolean executionIsolationThreadInterruptOnTimeout;
064    @XmlAttribute
065    @Metadata(label = "command", defaultValue = "1000")
066    private Integer executionTimeoutInMilliseconds;
067    @XmlAttribute
068    @Metadata(label = "command", defaultValue = "true")
069    private Boolean executionTimeoutEnabled;
070    @XmlAttribute
071    @Metadata(label = "command", defaultValue = "10")
072    private Integer fallbackIsolationSemaphoreMaxConcurrentRequests;
073    @XmlAttribute
074    @Metadata(label = "command", defaultValue = "true")
075    private Boolean fallbackEnabled;
076    @XmlAttribute
077    @Metadata(label = "command", defaultValue = "500")
078    private Integer metricsHealthSnapshotIntervalInMilliseconds;
079    @XmlAttribute
080    @Metadata(label = "command", defaultValue = "10")
081    private Integer metricsRollingPercentileBucketSize;
082    @XmlAttribute
083    @Metadata(label = "command", defaultValue = "true")
084    private Boolean metricsRollingPercentileEnabled;
085    @XmlAttribute
086    @Metadata(label = "command", defaultValue = "10000")
087    private Integer metricsRollingPercentileWindowInMilliseconds;
088    @XmlAttribute
089    @Metadata(label = "command", defaultValue = "6")
090    private Integer metricsRollingPercentileWindowBuckets;
091    @XmlAttribute
092    @Metadata(label = "command", defaultValue = "10000")
093    private Integer metricsRollingStatisticalWindowInMilliseconds;
094    @XmlAttribute
095    @Metadata(label = "command", defaultValue = "10")
096    private Integer metricsRollingStatisticalWindowBuckets;
097    @XmlAttribute
098    @Metadata(label = "command", defaultValue = "true")
099    private Boolean requestLogEnabled;
100
101    // thread-pool
102
103    @XmlAttribute
104    @Metadata(label = "threadpool", defaultValue = "10")
105    private Integer corePoolSize;
106    @XmlAttribute
107    @Metadata(label = "threadpool", defaultValue = "10")
108    private Integer maximumSize;
109    @XmlAttribute
110    @Metadata(label = "threadpool", defaultValue = "1")
111    private Integer keepAliveTime;
112    @XmlAttribute
113    @Metadata(label = "threadpool", defaultValue = "-1")
114    private Integer maxQueueSize;
115    @XmlAttribute
116    @Metadata(label = "threadpool", defaultValue = "5")
117    private Integer queueSizeRejectionThreshold;
118    @XmlAttribute
119    @Metadata(label = "threadpool", defaultValue = "10000")
120    private Integer threadPoolRollingNumberStatisticalWindowInMilliseconds;
121    @XmlAttribute
122    @Metadata(label = "threadpool", defaultValue = "10")
123    private Integer threadPoolRollingNumberStatisticalWindowBuckets;
124    @XmlAttribute
125    @Metadata(label = "threadpool", defaultValue = "false")
126    private Boolean allowMaximumSizeToDivergeFromCoreSize;
127
128
129    // Getter/Setter
130    // -------------------------------------------------------------------------
131
132    public String getGroupKey() {
133        return groupKey;
134    }
135
136    /**
137     * Sets the group key to use. The default value is CamelHystrix.
138     */
139    public void setGroupKey(String groupKey) {
140        this.groupKey = groupKey;
141    }
142
143    public String getThreadPoolKey() {
144        return threadPoolKey;
145    }
146
147    /**
148     * Sets the thread pool key to use. Will by default use the same value as groupKey has been configured to use.
149     */
150    public void setThreadPoolKey(String threadPoolKey) {
151        this.threadPoolKey = threadPoolKey;
152    }
153
154    public Boolean getCircuitBreakerEnabled() {
155        return circuitBreakerEnabled;
156    }
157
158    /**
159     * Whether to use a HystrixCircuitBreaker or not. If false no circuit-breaker logic will be used and all requests permitted.
160     * <p>
161     * This is similar in effect to circuitBreakerForceClosed() except that continues tracking metrics and knowing whether it
162     * should be open/closed, this property results in not even instantiating a circuit-breaker.
163     */
164    public void setCircuitBreakerEnabled(Boolean circuitBreakerEnabled) {
165        this.circuitBreakerEnabled = circuitBreakerEnabled;
166    }
167
168    public Integer getCircuitBreakerErrorThresholdPercentage() {
169        return circuitBreakerErrorThresholdPercentage;
170    }
171
172    /**
173     * Error percentage threshold (as whole number such as 50) at which point the circuit breaker will trip open and reject requests.
174     * <p>
175     * It will stay tripped for the duration defined in circuitBreakerSleepWindowInMilliseconds;
176     * <p>
177     * The error percentage this is compared against comes from HystrixCommandMetrics.getHealthCounts().
178     */
179    public void setCircuitBreakerErrorThresholdPercentage(Integer circuitBreakerErrorThresholdPercentage) {
180        this.circuitBreakerErrorThresholdPercentage = circuitBreakerErrorThresholdPercentage;
181    }
182
183    public Boolean getCircuitBreakerForceClosed() {
184        return circuitBreakerForceClosed;
185    }
186
187    /**
188     * If true the HystrixCircuitBreaker#allowRequest() will always return true to allow requests regardless of
189     * the error percentage from HystrixCommandMetrics.getHealthCounts().
190     * <p>
191     * The circuitBreakerForceOpen() property takes precedence so if it set to true this property does nothing.
192     */
193    public void setCircuitBreakerForceClosed(Boolean circuitBreakerForceClosed) {
194        this.circuitBreakerForceClosed = circuitBreakerForceClosed;
195    }
196
197    public Boolean getCircuitBreakerForceOpen() {
198        return circuitBreakerForceOpen;
199    }
200
201    /**
202     * If true the HystrixCircuitBreaker.allowRequest() will always return false, causing the circuit to be open (tripped) and reject all requests.
203     * <p>
204     * This property takes precedence over circuitBreakerForceClosed();
205     */
206    public void setCircuitBreakerForceOpen(Boolean circuitBreakerForceOpen) {
207        this.circuitBreakerForceOpen = circuitBreakerForceOpen;
208    }
209
210    public Integer getCircuitBreakerRequestVolumeThreshold() {
211        return circuitBreakerRequestVolumeThreshold;
212    }
213
214    /**
215     * Minimum number of requests in the metricsRollingStatisticalWindowInMilliseconds() that must exist before the HystrixCircuitBreaker will trip.
216     * <p>
217     * If below this number the circuit will not trip regardless of error percentage.
218     */
219    public void setCircuitBreakerRequestVolumeThreshold(Integer circuitBreakerRequestVolumeThreshold) {
220        this.circuitBreakerRequestVolumeThreshold = circuitBreakerRequestVolumeThreshold;
221    }
222
223    public Integer getCircuitBreakerSleepWindowInMilliseconds() {
224        return circuitBreakerSleepWindowInMilliseconds;
225    }
226
227    /**
228     * The time in milliseconds after a HystrixCircuitBreaker trips open that it should wait before trying requests again.
229     */
230    public void setCircuitBreakerSleepWindowInMilliseconds(Integer circuitBreakerSleepWindowInMilliseconds) {
231        this.circuitBreakerSleepWindowInMilliseconds = circuitBreakerSleepWindowInMilliseconds;
232    }
233
234    public Integer getExecutionIsolationSemaphoreMaxConcurrentRequests() {
235        return executionIsolationSemaphoreMaxConcurrentRequests;
236    }
237
238    /**
239     * Number of concurrent requests permitted to HystrixCommand.run(). Requests beyond the concurrent limit will be rejected.
240     * <p>
241     * Applicable only when executionIsolationStrategy == SEMAPHORE.
242     */
243    public void setExecutionIsolationSemaphoreMaxConcurrentRequests(Integer executionIsolationSemaphoreMaxConcurrentRequests) {
244        this.executionIsolationSemaphoreMaxConcurrentRequests = executionIsolationSemaphoreMaxConcurrentRequests;
245    }
246
247    public String getExecutionIsolationStrategy() {
248        return executionIsolationStrategy;
249    }
250
251    /**
252     * What isolation strategy HystrixCommand.run() will be executed with.
253     * <p>
254     * If THREAD then it will be executed on a separate thread and concurrent requests limited by the number of threads in the thread-pool.
255     * <p>
256     * If SEMAPHORE then it will be executed on the calling thread and concurrent requests limited by the semaphore count.
257     */
258    public void setExecutionIsolationStrategy(String executionIsolationStrategy) {
259        this.executionIsolationStrategy = executionIsolationStrategy;
260    }
261
262    public Boolean getExecutionIsolationThreadInterruptOnTimeout() {
263        return executionIsolationThreadInterruptOnTimeout;
264    }
265
266    /**
267     * Whether the execution thread should attempt an interrupt (using {@link Future#cancel}) when a thread times out.
268     * <p>
269     * Applicable only when executionIsolationStrategy() == THREAD.
270     */
271    public void setExecutionIsolationThreadInterruptOnTimeout(Boolean executionIsolationThreadInterruptOnTimeout) {
272        this.executionIsolationThreadInterruptOnTimeout = executionIsolationThreadInterruptOnTimeout;
273    }
274
275    public Integer getExecutionTimeoutInMilliseconds() {
276        return executionTimeoutInMilliseconds;
277    }
278
279    /**
280     * Time in milliseconds at which point the command will timeout and halt execution.
281     * <p>
282     * If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted.
283     * If the command is semaphore-isolated and a HystrixObservableCommand, that command will get unsubscribed.
284     */
285    public void setExecutionTimeoutInMilliseconds(Integer executionTimeoutInMilliseconds) {
286        this.executionTimeoutInMilliseconds = executionTimeoutInMilliseconds;
287    }
288
289    public Boolean getExecutionTimeoutEnabled() {
290        return executionTimeoutEnabled;
291    }
292    /**
293     * Whether the timeout mechanism is enabled for this command
294     */
295    public void setExecutionTimeoutEnabled(Boolean executionTimeoutEnabled) {
296        this.executionTimeoutEnabled = executionTimeoutEnabled;
297    }
298
299    public Integer getFallbackIsolationSemaphoreMaxConcurrentRequests() {
300        return fallbackIsolationSemaphoreMaxConcurrentRequests;
301    }
302
303    /**
304     * Number of concurrent requests permitted to HystrixCommand.getFallback().
305     * Requests beyond the concurrent limit will fail-fast and not attempt retrieving a fallback.
306     */
307    public void setFallbackIsolationSemaphoreMaxConcurrentRequests(Integer fallbackIsolationSemaphoreMaxConcurrentRequests) {
308        this.fallbackIsolationSemaphoreMaxConcurrentRequests = fallbackIsolationSemaphoreMaxConcurrentRequests;
309    }
310
311    public Boolean getFallbackEnabled() {
312        return fallbackEnabled;
313    }
314
315    /**
316     * Whether HystrixCommand.getFallback() should be attempted when failure occurs.
317     */
318    public void setFallbackEnabled(Boolean fallbackEnabled) {
319        this.fallbackEnabled = fallbackEnabled;
320    }
321
322    public Integer getMetricsHealthSnapshotIntervalInMilliseconds() {
323        return metricsHealthSnapshotIntervalInMilliseconds;
324    }
325
326    /**
327     * Time in milliseconds to wait between allowing health snapshots to be taken that calculate success and error
328     * percentages and affect HystrixCircuitBreaker.isOpen() status.
329     * <p>
330     * On high-volume circuits the continual calculation of error percentage can become CPU intensive thus this controls how often it is calculated.
331     */
332    public void setMetricsHealthSnapshotIntervalInMilliseconds(Integer metricsHealthSnapshotIntervalInMilliseconds) {
333        this.metricsHealthSnapshotIntervalInMilliseconds = metricsHealthSnapshotIntervalInMilliseconds;
334    }
335
336    public Integer getMetricsRollingPercentileBucketSize() {
337        return metricsRollingPercentileBucketSize;
338    }
339
340    /**
341     * Maximum number of values stored in each bucket of the rolling percentile.
342     * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics.
343     */
344    public void setMetricsRollingPercentileBucketSize(Integer metricsRollingPercentileBucketSize) {
345        this.metricsRollingPercentileBucketSize = metricsRollingPercentileBucketSize;
346    }
347
348    public Boolean getMetricsRollingPercentileEnabled() {
349        return metricsRollingPercentileEnabled;
350    }
351
352    /**
353     * Whether percentile metrics should be captured using HystrixRollingPercentile inside HystrixCommandMetrics.
354     */
355    public void setMetricsRollingPercentileEnabled(Boolean metricsRollingPercentileEnabled) {
356        this.metricsRollingPercentileEnabled = metricsRollingPercentileEnabled;
357    }
358
359    public Integer getMetricsRollingPercentileWindowInMilliseconds() {
360        return metricsRollingPercentileWindowInMilliseconds;
361    }
362
363    /**
364     * Duration of percentile rolling window in milliseconds.
365     * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics.
366     */
367    public void setMetricsRollingPercentileWindowInMilliseconds(Integer metricsRollingPercentileWindowInMilliseconds) {
368        this.metricsRollingPercentileWindowInMilliseconds = metricsRollingPercentileWindowInMilliseconds;
369    }
370
371    public Integer getMetricsRollingPercentileWindowBuckets() {
372        return metricsRollingPercentileWindowBuckets;
373    }
374
375    /**
376     * Number of buckets the rolling percentile window is broken into.
377     * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics.
378     */
379    public void setMetricsRollingPercentileWindowBuckets(Integer metricsRollingPercentileWindowBuckets) {
380        this.metricsRollingPercentileWindowBuckets = metricsRollingPercentileWindowBuckets;
381    }
382
383    public Integer getMetricsRollingStatisticalWindowInMilliseconds() {
384        return metricsRollingStatisticalWindowInMilliseconds;
385    }
386
387    /**
388     * This property sets the duration of the statistical rolling window, in milliseconds. This is how long metrics are kept for the thread pool.
389     *
390     * The window is divided into buckets and “rolls” by those increments.
391     */
392    public void setMetricsRollingStatisticalWindowInMilliseconds(Integer metricsRollingStatisticalWindowInMilliseconds) {
393        this.metricsRollingStatisticalWindowInMilliseconds = metricsRollingStatisticalWindowInMilliseconds;
394    }
395
396    public Integer getMetricsRollingStatisticalWindowBuckets() {
397        return metricsRollingStatisticalWindowBuckets;
398    }
399
400    /**
401     * Number of buckets the rolling statistical window is broken into.
402     * This is passed into HystrixRollingNumber inside HystrixCommandMetrics.
403     */
404    public void setMetricsRollingStatisticalWindowBuckets(Integer metricsRollingStatisticalWindowBuckets) {
405        this.metricsRollingStatisticalWindowBuckets = metricsRollingStatisticalWindowBuckets;
406    }
407
408    public Boolean getRequestLogEnabled() {
409        return requestLogEnabled;
410    }
411
412    /**
413     * Whether HystrixCommand execution and events should be logged to HystrixRequestLog.
414     */
415    public void setRequestLogEnabled(Boolean requestLogEnabled) {
416        this.requestLogEnabled = requestLogEnabled;
417    }
418
419    public Integer getCorePoolSize() {
420        return corePoolSize;
421    }
422
423    /**
424     * Core thread-pool size that gets passed to {@link java.util.concurrent.ThreadPoolExecutor#setCorePoolSize(int)}
425     */
426    public void setCorePoolSize(Integer corePoolSize) {
427        this.corePoolSize = corePoolSize;
428    }
429
430    public Integer getMaximumSize() {
431        return maximumSize;
432    }
433
434    /**
435     * Maximum thread-pool size that gets passed to {@link ThreadPoolExecutor#setMaximumPoolSize(int)}.
436     * This is the maximum amount of concurrency that can be supported without starting to reject HystrixCommands.
437     * Please note that this setting only takes effect if you also set allowMaximumSizeToDivergeFromCoreSize
438     */
439    public void setMaximumSize(Integer maximumSize) {
440        this.maximumSize = maximumSize;
441    }
442
443    public Integer getKeepAliveTime() {
444        return keepAliveTime;
445    }
446
447    /**
448     * Keep-alive time in minutes that gets passed to {@link ThreadPoolExecutor#setKeepAliveTime(long, TimeUnit)}
449     */
450    public void setKeepAliveTime(Integer keepAliveTime) {
451        this.keepAliveTime = keepAliveTime;
452    }
453
454    public Integer getMaxQueueSize() {
455        return maxQueueSize;
456    }
457
458    /**
459     * Max queue size that gets passed to {@link BlockingQueue} in HystrixConcurrencyStrategy.getBlockingQueue(int)
460     *
461     * This should only affect the instantiation of a threadpool - it is not eliglible to change a queue size on the fly.
462     * For that, use queueSizeRejectionThreshold().
463     */
464    public void setMaxQueueSize(Integer maxQueueSize) {
465        this.maxQueueSize = maxQueueSize;
466    }
467
468    public Integer getQueueSizeRejectionThreshold() {
469        return queueSizeRejectionThreshold;
470    }
471
472    /**
473     * Queue size rejection threshold is an artificial "max" size at which rejections will occur even
474     * if {@link #maxQueueSize} has not been reached. This is done because the {@link #maxQueueSize}
475     * of a {@link BlockingQueue} can not be dynamically changed and we want to support dynamically
476     * changing the queue size that affects rejections.
477     * <p>
478     * This is used by HystrixCommand when queuing a thread for execution.
479     */
480    public void setQueueSizeRejectionThreshold(Integer queueSizeRejectionThreshold) {
481        this.queueSizeRejectionThreshold = queueSizeRejectionThreshold;
482    }
483
484    public Integer getThreadPoolRollingNumberStatisticalWindowInMilliseconds() {
485        return threadPoolRollingNumberStatisticalWindowInMilliseconds;
486    }
487
488    /**
489     * Duration of statistical rolling window in milliseconds.
490     * This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance.
491     */
492    public void setThreadPoolRollingNumberStatisticalWindowInMilliseconds(Integer threadPoolRollingNumberStatisticalWindowInMilliseconds) {
493        this.threadPoolRollingNumberStatisticalWindowInMilliseconds = threadPoolRollingNumberStatisticalWindowInMilliseconds;
494    }
495
496    public Integer getThreadPoolRollingNumberStatisticalWindowBuckets() {
497        return threadPoolRollingNumberStatisticalWindowBuckets;
498    }
499
500    /**
501     * Number of buckets the rolling statistical window is broken into.
502     * This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance.
503     */
504    public void setThreadPoolRollingNumberStatisticalWindowBuckets(Integer threadPoolRollingNumberStatisticalWindowBuckets) {
505        this.threadPoolRollingNumberStatisticalWindowBuckets = threadPoolRollingNumberStatisticalWindowBuckets;
506    }
507
508    public Boolean getAllowMaximumSizeToDivergeFromCoreSize() {
509        return allowMaximumSizeToDivergeFromCoreSize;
510    }
511
512    /**
513     * Allows the configuration for maximumSize to take effect. That value can then be equal to, or higher, than coreSize
514     */
515    public void setAllowMaximumSizeToDivergeFromCoreSize(Boolean allowMaximumSizeToDivergeFromCoreSize) {
516        this.allowMaximumSizeToDivergeFromCoreSize = allowMaximumSizeToDivergeFromCoreSize;
517    }
518}