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