This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new fcf913c CAMEL-13354: Camel Main can now configure Hystrix EIP fcf913c is described below commit fcf913c38ad0eb635629816dc577c31e5414e63b Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Jun 12 09:42:01 2019 +0200 CAMEL-13354: Camel Main can now configure Hystrix EIP --- .../camel/main/HystrixConfigurationProperties.java | 760 +++++++++++++++++++++ .../camel/main/MainConfigurationProperties.java | 7 + .../java/org/apache/camel/main/MainSupport.java | 23 +- .../src/main/resources/application.properties | 3 + 4 files changed, 790 insertions(+), 3 deletions(-) diff --git a/core/camel-main/src/main/java/org/apache/camel/main/HystrixConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/HystrixConfigurationProperties.java new file mode 100644 index 0000000..b81d7d1 --- /dev/null +++ b/core/camel-main/src/main/java/org/apache/camel/main/HystrixConfigurationProperties.java @@ -0,0 +1,760 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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 org.apache.camel.main; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Global configuration for Hystrix EIP circuit breaker. + */ +public class HystrixConfigurationProperties { + + private final MainConfigurationProperties parent; + + private String groupKey; + private String threadPoolKey; + private Boolean circuitBreakerEnabled; + private Integer circuitBreakerErrorThresholdPercentage; + private Boolean circuitBreakerForceClosed; + private Boolean circuitBreakerForceOpen; + private Integer circuitBreakerRequestVolumeThreshold; + private Integer circuitBreakerSleepWindowInMilliseconds; + private Integer executionIsolationSemaphoreMaxConcurrentRequests; + private String executionIsolationStrategy; + private Boolean executionIsolationThreadInterruptOnTimeout; + private Integer executionTimeoutInMilliseconds; + private Boolean executionTimeoutEnabled; + private Integer fallbackIsolationSemaphoreMaxConcurrentRequests; + private Boolean fallbackEnabled; + private Integer metricsHealthSnapshotIntervalInMilliseconds; + private Integer metricsRollingPercentileBucketSize; + private Boolean metricsRollingPercentileEnabled; + private Integer metricsRollingPercentileWindowInMilliseconds; + private Integer metricsRollingPercentileWindowBuckets; + private Integer metricsRollingStatisticalWindowInMilliseconds; + private Integer metricsRollingStatisticalWindowBuckets; + private Boolean requestLogEnabled; + // thread-pool + private Integer corePoolSize; + private Integer maximumSize; + private Integer keepAliveTime; + private Integer maxQueueSize; + private Integer queueSizeRejectionThreshold; + private Integer threadPoolRollingNumberStatisticalWindowInMilliseconds; + private Integer threadPoolRollingNumberStatisticalWindowBuckets; + private Boolean allowMaximumSizeToDivergeFromCoreSize; + + public HystrixConfigurationProperties(MainConfigurationProperties parent) { + this.parent = parent; + } + + public MainConfigurationProperties end() { + return parent; + } + + // getter and setters + // -------------------------------------------------------------- + + public String getGroupKey() { + return groupKey; + } + + /** + * Sets the group key to use. The default value is CamelHystrix. + */ + public void setGroupKey(String groupKey) { + this.groupKey = groupKey; + } + + public String getThreadPoolKey() { + return threadPoolKey; + } + + /** + * Sets the thread pool key to use. Will by default use the same value as groupKey has been configured to use. + */ + public void setThreadPoolKey(String threadPoolKey) { + this.threadPoolKey = threadPoolKey; + } + + public Boolean getCircuitBreakerEnabled() { + return circuitBreakerEnabled; + } + + /** + * Whether to use a HystrixCircuitBreaker or not. If false no circuit-breaker logic will be used and all requests permitted. + * <p> + * This is similar in effect to circuitBreakerForceClosed() except that continues tracking metrics and knowing whether it + * should be open/closed, this property results in not even instantiating a circuit-breaker. + */ + public void setCircuitBreakerEnabled(Boolean circuitBreakerEnabled) { + this.circuitBreakerEnabled = circuitBreakerEnabled; + } + + public Integer getCircuitBreakerErrorThresholdPercentage() { + return circuitBreakerErrorThresholdPercentage; + } + + /** + * Error percentage threshold (as whole number such as 50) at which point the circuit breaker will trip open and reject requests. + * <p> + * It will stay tripped for the duration defined in circuitBreakerSleepWindowInMilliseconds; + * <p> + * The error percentage this is compared against comes from HystrixCommandMetrics.getHealthCounts(). + */ + public void setCircuitBreakerErrorThresholdPercentage(Integer circuitBreakerErrorThresholdPercentage) { + this.circuitBreakerErrorThresholdPercentage = circuitBreakerErrorThresholdPercentage; + } + + public Boolean getCircuitBreakerForceClosed() { + return circuitBreakerForceClosed; + } + + /** + * If true the HystrixCircuitBreaker#allowRequest() will always return true to allow requests regardless of + * the error percentage from HystrixCommandMetrics.getHealthCounts(). + * <p> + * The circuitBreakerForceOpen() property takes precedence so if it set to true this property does nothing. + */ + public void setCircuitBreakerForceClosed(Boolean circuitBreakerForceClosed) { + this.circuitBreakerForceClosed = circuitBreakerForceClosed; + } + + public Boolean getCircuitBreakerForceOpen() { + return circuitBreakerForceOpen; + } + + /** + * If true the HystrixCircuitBreaker.allowRequest() will always return false, causing the circuit to be open (tripped) and reject all requests. + * <p> + * This property takes precedence over circuitBreakerForceClosed(); + */ + public void setCircuitBreakerForceOpen(Boolean circuitBreakerForceOpen) { + this.circuitBreakerForceOpen = circuitBreakerForceOpen; + } + + public Integer getCircuitBreakerRequestVolumeThreshold() { + return circuitBreakerRequestVolumeThreshold; + } + + /** + * Minimum number of requests in the metricsRollingStatisticalWindowInMilliseconds() that must exist before the HystrixCircuitBreaker will trip. + * <p> + * If below this number the circuit will not trip regardless of error percentage. + */ + public void setCircuitBreakerRequestVolumeThreshold(Integer circuitBreakerRequestVolumeThreshold) { + this.circuitBreakerRequestVolumeThreshold = circuitBreakerRequestVolumeThreshold; + } + + public Integer getCircuitBreakerSleepWindowInMilliseconds() { + return circuitBreakerSleepWindowInMilliseconds; + } + + /** + * The time in milliseconds after a HystrixCircuitBreaker trips open that it should wait before trying requests again. + */ + public void setCircuitBreakerSleepWindowInMilliseconds(Integer circuitBreakerSleepWindowInMilliseconds) { + this.circuitBreakerSleepWindowInMilliseconds = circuitBreakerSleepWindowInMilliseconds; + } + + public Integer getExecutionIsolationSemaphoreMaxConcurrentRequests() { + return executionIsolationSemaphoreMaxConcurrentRequests; + } + + /** + * Number of concurrent requests permitted to HystrixCommand.run(). Requests beyond the concurrent limit will be rejected. + * <p> + * Applicable only when executionIsolationStrategy == SEMAPHORE. + */ + public void setExecutionIsolationSemaphoreMaxConcurrentRequests(Integer executionIsolationSemaphoreMaxConcurrentRequests) { + this.executionIsolationSemaphoreMaxConcurrentRequests = executionIsolationSemaphoreMaxConcurrentRequests; + } + + public String getExecutionIsolationStrategy() { + return executionIsolationStrategy; + } + + /** + * What isolation strategy HystrixCommand.run() will be executed with. + * <p> + * If THREAD then it will be executed on a separate thread and concurrent requests limited by the number of threads in the thread-pool. + * <p> + * If SEMAPHORE then it will be executed on the calling thread and concurrent requests limited by the semaphore count. + */ + public void setExecutionIsolationStrategy(String executionIsolationStrategy) { + this.executionIsolationStrategy = executionIsolationStrategy; + } + + public Boolean getExecutionIsolationThreadInterruptOnTimeout() { + return executionIsolationThreadInterruptOnTimeout; + } + + /** + * Whether the execution thread should attempt an interrupt (using {@link Future#cancel}) when a thread times out. + * <p> + * Applicable only when executionIsolationStrategy() == THREAD. + */ + public void setExecutionIsolationThreadInterruptOnTimeout(Boolean executionIsolationThreadInterruptOnTimeout) { + this.executionIsolationThreadInterruptOnTimeout = executionIsolationThreadInterruptOnTimeout; + } + + public Integer getExecutionTimeoutInMilliseconds() { + return executionTimeoutInMilliseconds; + } + + /** + * Time in milliseconds at which point the command will timeout and halt execution. + * <p> + * If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted. + * If the command is semaphore-isolated and a HystrixObservableCommand, that command will get unsubscribed. + */ + public void setExecutionTimeoutInMilliseconds(Integer executionTimeoutInMilliseconds) { + this.executionTimeoutInMilliseconds = executionTimeoutInMilliseconds; + } + + public Boolean getExecutionTimeoutEnabled() { + return executionTimeoutEnabled; + } + + /** + * Whether the timeout mechanism is enabled for this command + */ + public void setExecutionTimeoutEnabled(Boolean executionTimeoutEnabled) { + this.executionTimeoutEnabled = executionTimeoutEnabled; + } + + public Integer getFallbackIsolationSemaphoreMaxConcurrentRequests() { + return fallbackIsolationSemaphoreMaxConcurrentRequests; + } + + /** + * Number of concurrent requests permitted to HystrixCommand.getFallback(). + * Requests beyond the concurrent limit will fail-fast and not attempt retrieving a fallback. + */ + public void setFallbackIsolationSemaphoreMaxConcurrentRequests(Integer fallbackIsolationSemaphoreMaxConcurrentRequests) { + this.fallbackIsolationSemaphoreMaxConcurrentRequests = fallbackIsolationSemaphoreMaxConcurrentRequests; + } + + public Boolean getFallbackEnabled() { + return fallbackEnabled; + } + + /** + * Whether HystrixCommand.getFallback() should be attempted when failure occurs. + */ + public void setFallbackEnabled(Boolean fallbackEnabled) { + this.fallbackEnabled = fallbackEnabled; + } + + public Integer getMetricsHealthSnapshotIntervalInMilliseconds() { + return metricsHealthSnapshotIntervalInMilliseconds; + } + + /** + * Time in milliseconds to wait between allowing health snapshots to be taken that calculate success and error + * percentages and affect HystrixCircuitBreaker.isOpen() status. + * <p> + * On high-volume circuits the continual calculation of error percentage can become CPU intensive thus this controls how often it is calculated. + */ + public void setMetricsHealthSnapshotIntervalInMilliseconds(Integer metricsHealthSnapshotIntervalInMilliseconds) { + this.metricsHealthSnapshotIntervalInMilliseconds = metricsHealthSnapshotIntervalInMilliseconds; + } + + public Integer getMetricsRollingPercentileBucketSize() { + return metricsRollingPercentileBucketSize; + } + + /** + * Maximum number of values stored in each bucket of the rolling percentile. + * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public void setMetricsRollingPercentileBucketSize(Integer metricsRollingPercentileBucketSize) { + this.metricsRollingPercentileBucketSize = metricsRollingPercentileBucketSize; + } + + public Boolean getMetricsRollingPercentileEnabled() { + return metricsRollingPercentileEnabled; + } + + /** + * Whether percentile metrics should be captured using HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public void setMetricsRollingPercentileEnabled(Boolean metricsRollingPercentileEnabled) { + this.metricsRollingPercentileEnabled = metricsRollingPercentileEnabled; + } + + public Integer getMetricsRollingPercentileWindowInMilliseconds() { + return metricsRollingPercentileWindowInMilliseconds; + } + + /** + * Duration of percentile rolling window in milliseconds. + * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public void setMetricsRollingPercentileWindowInMilliseconds(Integer metricsRollingPercentileWindowInMilliseconds) { + this.metricsRollingPercentileWindowInMilliseconds = metricsRollingPercentileWindowInMilliseconds; + } + + public Integer getMetricsRollingPercentileWindowBuckets() { + return metricsRollingPercentileWindowBuckets; + } + + /** + * Number of buckets the rolling percentile window is broken into. + * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public void setMetricsRollingPercentileWindowBuckets(Integer metricsRollingPercentileWindowBuckets) { + this.metricsRollingPercentileWindowBuckets = metricsRollingPercentileWindowBuckets; + } + + public Integer getMetricsRollingStatisticalWindowInMilliseconds() { + return metricsRollingStatisticalWindowInMilliseconds; + } + + /** + * This property sets the duration of the statistical rolling window, in milliseconds. This is how long metrics are kept for the thread pool. + * + * The window is divided into buckets and “rolls” by those increments. + */ + public void setMetricsRollingStatisticalWindowInMilliseconds(Integer metricsRollingStatisticalWindowInMilliseconds) { + this.metricsRollingStatisticalWindowInMilliseconds = metricsRollingStatisticalWindowInMilliseconds; + } + + public Integer getMetricsRollingStatisticalWindowBuckets() { + return metricsRollingStatisticalWindowBuckets; + } + + /** + * Number of buckets the rolling statistical window is broken into. + * This is passed into HystrixRollingNumber inside HystrixCommandMetrics. + */ + public void setMetricsRollingStatisticalWindowBuckets(Integer metricsRollingStatisticalWindowBuckets) { + this.metricsRollingStatisticalWindowBuckets = metricsRollingStatisticalWindowBuckets; + } + + public Boolean getRequestLogEnabled() { + return requestLogEnabled; + } + + /** + * Whether HystrixCommand execution and events should be logged to HystrixRequestLog. + */ + public void setRequestLogEnabled(Boolean requestLogEnabled) { + this.requestLogEnabled = requestLogEnabled; + } + + public Integer getCorePoolSize() { + return corePoolSize; + } + + /** + * Core thread-pool size that gets passed to {@link java.util.concurrent.ThreadPoolExecutor#setCorePoolSize(int)} + */ + public void setCorePoolSize(Integer corePoolSize) { + this.corePoolSize = corePoolSize; + } + + public Integer getMaximumSize() { + return maximumSize; + } + + /** + * Maximum thread-pool size that gets passed to {@link ThreadPoolExecutor#setMaximumPoolSize(int)}. + * This is the maximum amount of concurrency that can be supported without starting to reject HystrixCommands. + * Please note that this setting only takes effect if you also set allowMaximumSizeToDivergeFromCoreSize + */ + public void setMaximumSize(Integer maximumSize) { + this.maximumSize = maximumSize; + } + + public Integer getKeepAliveTime() { + return keepAliveTime; + } + + /** + * Keep-alive time in minutes that gets passed to {@link ThreadPoolExecutor#setKeepAliveTime(long, TimeUnit)} + */ + public void setKeepAliveTime(Integer keepAliveTime) { + this.keepAliveTime = keepAliveTime; + } + + public Integer getMaxQueueSize() { + return maxQueueSize; + } + + /** + * Max queue size that gets passed to {@link BlockingQueue} in 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 queueSizeRejectionThreshold(). + */ + public void setMaxQueueSize(Integer maxQueueSize) { + this.maxQueueSize = maxQueueSize; + } + + public Integer getQueueSizeRejectionThreshold() { + return queueSizeRejectionThreshold; + } + + /** + * 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 HystrixCommand when queuing a thread for execution. + */ + public void setQueueSizeRejectionThreshold(Integer queueSizeRejectionThreshold) { + this.queueSizeRejectionThreshold = queueSizeRejectionThreshold; + } + + public Integer getThreadPoolRollingNumberStatisticalWindowInMilliseconds() { + return threadPoolRollingNumberStatisticalWindowInMilliseconds; + } + + /** + * Duration of statistical rolling window in milliseconds. + * This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance. + */ + public void setThreadPoolRollingNumberStatisticalWindowInMilliseconds(Integer threadPoolRollingNumberStatisticalWindowInMilliseconds) { + this.threadPoolRollingNumberStatisticalWindowInMilliseconds = threadPoolRollingNumberStatisticalWindowInMilliseconds; + } + + public Integer getThreadPoolRollingNumberStatisticalWindowBuckets() { + return threadPoolRollingNumberStatisticalWindowBuckets; + } + + /** + * Number of buckets the rolling statistical window is broken into. + * This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance. + */ + public void setThreadPoolRollingNumberStatisticalWindowBuckets(Integer threadPoolRollingNumberStatisticalWindowBuckets) { + this.threadPoolRollingNumberStatisticalWindowBuckets = threadPoolRollingNumberStatisticalWindowBuckets; + } + + public Boolean getAllowMaximumSizeToDivergeFromCoreSize() { + return allowMaximumSizeToDivergeFromCoreSize; + } + + /** + * Allows the configuration for maximumSize to take effect. That value can then be equal to, or higher, than coreSize + */ + public void setAllowMaximumSizeToDivergeFromCoreSize(Boolean allowMaximumSizeToDivergeFromCoreSize) { + this.allowMaximumSizeToDivergeFromCoreSize = allowMaximumSizeToDivergeFromCoreSize; + } + + // fluent builders + // -------------------------------------------------------------- + + /** + * Sets the group key to use. The default value is CamelHystrix. + */ + public HystrixConfigurationProperties withGroupKey(String groupKey) { + this.groupKey = groupKey; + return this; + } + + /** + * Sets the thread pool key to use. Will by default use the same value as groupKey has been configured to use. + */ + public HystrixConfigurationProperties withThreadPoolKey(String threadPoolKey) { + this.threadPoolKey = threadPoolKey; + return this; + } + + /** + * Whether to use a HystrixCircuitBreaker or not. If false no circuit-breaker logic will be used and all requests permitted. + * <p> + * This is similar in effect to circuitBreakerForceClosed() except that continues tracking metrics and knowing whether it + * should be open/closed, this property results in not even instantiating a circuit-breaker. + */ + public HystrixConfigurationProperties withCircuitBreakerEnabled(Boolean circuitBreakerEnabled) { + this.circuitBreakerEnabled = circuitBreakerEnabled; + return this; + } + + /** + * Error percentage threshold (as whole number such as 50) at which point the circuit breaker will trip open and reject requests. + * <p> + * It will stay tripped for the duration defined in circuitBreakerSleepWindowInMilliseconds; + * <p> + * The error percentage this is compared against comes from HystrixCommandMetrics.getHealthCounts(). + */ + public HystrixConfigurationProperties withCircuitBreakerErrorThresholdPercentage(Integer circuitBreakerErrorThresholdPercentage) { + this.circuitBreakerErrorThresholdPercentage = circuitBreakerErrorThresholdPercentage; + return this; + } + + /** + * If true the HystrixCircuitBreaker#allowRequest() will always return true to allow requests regardless of + * the error percentage from HystrixCommandMetrics.getHealthCounts(). + * <p> + * The circuitBreakerForceOpen() property takes precedence so if it set to true this property does nothing. + */ + public HystrixConfigurationProperties withCircuitBreakerForceClosed(Boolean circuitBreakerForceClosed) { + this.circuitBreakerForceClosed = circuitBreakerForceClosed; + return this; + } + + /** + * If true the HystrixCircuitBreaker.allowRequest() will always return false, causing the circuit to be open (tripped) and reject all requests. + * <p> + * This property takes precedence over circuitBreakerForceClosed(); + */ + public HystrixConfigurationProperties withCircuitBreakerForceOpen(Boolean circuitBreakerForceOpen) { + this.circuitBreakerForceOpen = circuitBreakerForceOpen; + return this; + } + + /** + * Minimum number of requests in the metricsRollingStatisticalWindowInMilliseconds() that must exist before the HystrixCircuitBreaker will trip. + * <p> + * If below this number the circuit will not trip regardless of error percentage. + */ + public HystrixConfigurationProperties withCircuitBreakerRequestVolumeThreshold(Integer circuitBreakerRequestVolumeThreshold) { + this.circuitBreakerRequestVolumeThreshold = circuitBreakerRequestVolumeThreshold; + return this; + } + + /** + * The time in milliseconds after a HystrixCircuitBreaker trips open that it should wait before trying requests again. + */ + public HystrixConfigurationProperties withCircuitBreakerSleepWindowInMilliseconds(Integer circuitBreakerSleepWindowInMilliseconds) { + this.circuitBreakerSleepWindowInMilliseconds = circuitBreakerSleepWindowInMilliseconds; + return this; + } + + /** + * Number of concurrent requests permitted to HystrixCommand.run(). Requests beyond the concurrent limit will be rejected. + * <p> + * Applicable only when executionIsolationStrategy == SEMAPHORE. + */ + public HystrixConfigurationProperties withExecutionIsolationSemaphoreMaxConcurrentRequests(Integer executionIsolationSemaphoreMaxConcurrentRequests) { + this.executionIsolationSemaphoreMaxConcurrentRequests = executionIsolationSemaphoreMaxConcurrentRequests; + return this; + } + + /** + * What isolation strategy HystrixCommand.run() will be executed with. + * <p> + * If THREAD then it will be executed on a separate thread and concurrent requests limited by the number of threads in the thread-pool. + * <p> + * If SEMAPHORE then it will be executed on the calling thread and concurrent requests limited by the semaphore count. + */ + public HystrixConfigurationProperties withExecutionIsolationStrategy(String executionIsolationStrategy) { + this.executionIsolationStrategy = executionIsolationStrategy; + return this; + } + + /** + * Whether the execution thread should attempt an interrupt (using {@link Future#cancel}) when a thread times out. + * <p> + * Applicable only when executionIsolationStrategy() == THREAD. + */ + public HystrixConfigurationProperties withExecutionIsolationThreadInterruptOnTimeout(Boolean executionIsolationThreadInterruptOnTimeout) { + this.executionIsolationThreadInterruptOnTimeout = executionIsolationThreadInterruptOnTimeout; + return this; + } + + /** + * Time in milliseconds at which point the command will timeout and halt execution. + * <p> + * If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted. + * If the command is semaphore-isolated and a HystrixObservableCommand, that command will get unsubscribed. + */ + public HystrixConfigurationProperties withExecutionTimeoutInMilliseconds(Integer executionTimeoutInMilliseconds) { + this.executionTimeoutInMilliseconds = executionTimeoutInMilliseconds; + return this; + } + + /** + * Whether the timeout mechanism is enabled for this command + */ + public HystrixConfigurationProperties withExecutionTimeoutEnabled(Boolean executionTimeoutEnabled) { + this.executionTimeoutEnabled = executionTimeoutEnabled; + return this; + } + + /** + * Number of concurrent requests permitted to HystrixCommand.getFallback(). + * Requests beyond the concurrent limit will fail-fast and not attempt retrieving a fallback. + */ + public HystrixConfigurationProperties withFallbackIsolationSemaphoreMaxConcurrentRequests(Integer fallbackIsolationSemaphoreMaxConcurrentRequests) { + this.fallbackIsolationSemaphoreMaxConcurrentRequests = fallbackIsolationSemaphoreMaxConcurrentRequests; + return this; + } + + /** + * Whether HystrixCommand.getFallback() should be attempted when failure occurs. + */ + public HystrixConfigurationProperties withFallbackEnabled(Boolean fallbackEnabled) { + this.fallbackEnabled = fallbackEnabled; + return this; + } + + /** + * Time in milliseconds to wait between allowing health snapshots to be taken that calculate success and error + * percentages and affect HystrixCircuitBreaker.isOpen() status. + * <p> + * On high-volume circuits the continual calculation of error percentage can become CPU intensive thus this controls how often it is calculated. + */ + public HystrixConfigurationProperties withMetricsHealthSnapshotIntervalInMilliseconds(Integer metricsHealthSnapshotIntervalInMilliseconds) { + this.metricsHealthSnapshotIntervalInMilliseconds = metricsHealthSnapshotIntervalInMilliseconds; + return this; + } + + /** + * Maximum number of values stored in each bucket of the rolling percentile. + * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public HystrixConfigurationProperties withMetricsRollingPercentileBucketSize(Integer metricsRollingPercentileBucketSize) { + this.metricsRollingPercentileBucketSize = metricsRollingPercentileBucketSize; + return this; + } + + /** + * Whether percentile metrics should be captured using HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public HystrixConfigurationProperties withMetricsRollingPercentileEnabled(Boolean metricsRollingPercentileEnabled) { + this.metricsRollingPercentileEnabled = metricsRollingPercentileEnabled; + return this; + } + + /** + * Duration of percentile rolling window in milliseconds. + * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public HystrixConfigurationProperties withMetricsRollingPercentileWindowInMilliseconds(Integer metricsRollingPercentileWindowInMilliseconds) { + this.metricsRollingPercentileWindowInMilliseconds = metricsRollingPercentileWindowInMilliseconds; + return this; + } + + /** + * Number of buckets the rolling percentile window is broken into. + * This is passed into HystrixRollingPercentile inside HystrixCommandMetrics. + */ + public HystrixConfigurationProperties withMetricsRollingPercentileWindowBuckets(Integer metricsRollingPercentileWindowBuckets) { + this.metricsRollingPercentileWindowBuckets = metricsRollingPercentileWindowBuckets; + return this; + } + + /** + * This property sets the duration of the statistical rolling window, in milliseconds. This is how long metrics are kept for the thread pool. + * + * The window is divided into buckets and “rolls” by those increments. + */ + public HystrixConfigurationProperties withMetricsRollingStatisticalWindowInMilliseconds(Integer metricsRollingStatisticalWindowInMilliseconds) { + this.metricsRollingStatisticalWindowInMilliseconds = metricsRollingStatisticalWindowInMilliseconds; + return this; + } + + /** + * Number of buckets the rolling statistical window is broken into. + * This is passed into HystrixRollingNumber inside HystrixCommandMetrics. + */ + public HystrixConfigurationProperties withMetricsRollingStatisticalWindowBuckets(Integer metricsRollingStatisticalWindowBuckets) { + this.metricsRollingStatisticalWindowBuckets = metricsRollingStatisticalWindowBuckets; + return this; + } + + /** + * Whether HystrixCommand execution and events should be logged to HystrixRequestLog. + */ + public HystrixConfigurationProperties withRequestLogEnabled(Boolean requestLogEnabled) { + this.requestLogEnabled = requestLogEnabled; + return this; + } + + /** + * Core thread-pool size that gets passed to {@link java.util.concurrent.ThreadPoolExecutor#setCorePoolSize(int)} + */ + public HystrixConfigurationProperties withCorePoolSize(Integer corePoolSize) { + this.corePoolSize = corePoolSize; + return this; + } + + /** + * Maximum thread-pool size that gets passed to {@link ThreadPoolExecutor#setMaximumPoolSize(int)}. + * This is the maximum amount of concurrency that can be supported without starting to reject HystrixCommands. + * Please note that this setting only takes effect if you also set allowMaximumSizeToDivergeFromCoreSize + */ + public HystrixConfigurationProperties withMaximumSize(Integer maximumSize) { + this.maximumSize = maximumSize; + return this; + } + + /** + * Keep-alive time in minutes that gets passed to {@link ThreadPoolExecutor#setKeepAliveTime(long, TimeUnit)} + */ + public HystrixConfigurationProperties withKeepAliveTime(Integer keepAliveTime) { + this.keepAliveTime = keepAliveTime; + return this; + } + + /** + * Max queue size that gets passed to {@link BlockingQueue} in 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 queueSizeRejectionThreshold(). + */ + public HystrixConfigurationProperties withMaxQueueSize(Integer maxQueueSize) { + this.maxQueueSize = maxQueueSize; + return this; + } + + /** + * 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 HystrixCommand when queuing a thread for execution. + */ + public HystrixConfigurationProperties withQueueSizeRejectionThreshold(Integer queueSizeRejectionThreshold) { + this.queueSizeRejectionThreshold = queueSizeRejectionThreshold; + return this; + } + + /** + * Duration of statistical rolling window in milliseconds. + * This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance. + */ + public HystrixConfigurationProperties withThreadPoolRollingNumberStatisticalWindowInMilliseconds(Integer threadPoolRollingNumberStatisticalWindowInMilliseconds) { + this.threadPoolRollingNumberStatisticalWindowInMilliseconds = threadPoolRollingNumberStatisticalWindowInMilliseconds; + return this; + } + + /** + * Number of buckets the rolling statistical window is broken into. + * This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance. + */ + public HystrixConfigurationProperties withThreadPoolRollingNumberStatisticalWindowBuckets(Integer threadPoolRollingNumberStatisticalWindowBuckets) { + this.threadPoolRollingNumberStatisticalWindowBuckets = threadPoolRollingNumberStatisticalWindowBuckets; + return this; + } + + /** + * Allows the configuration for maximumSize to take effect. That value can then be equal to, or higher, than coreSize + */ + public HystrixConfigurationProperties withAllowMaximumSizeToDivergeFromCoreSize(Boolean allowMaximumSizeToDivergeFromCoreSize) { + this.allowMaximumSizeToDivergeFromCoreSize = allowMaximumSizeToDivergeFromCoreSize; + return this; + } +} diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java index c867455..eb1d255 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java @@ -28,6 +28,9 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< private int durationHitExitCode; private boolean hangupInterceptorEnabled = true; + // extended configuration + private final HystrixConfigurationProperties hystrixConfigurationProperties = new HystrixConfigurationProperties(this); + // getter and setters // -------------------------------------------------------------- @@ -198,4 +201,8 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< return this; } + public HystrixConfigurationProperties hystrix() { + return hystrixConfigurationProperties; + } + } diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java index d4ad59a..d8e1e8a 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java @@ -37,7 +37,9 @@ import org.apache.camel.Component; import org.apache.camel.ExtendedCamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.HystrixConfigurationDefinition; import org.apache.camel.model.Model; +import org.apache.camel.model.ModelCamelContext; import org.apache.camel.model.RouteDefinition; import org.apache.camel.spi.CamelBeanPostProcessor; import org.apache.camel.spi.DataFormat; @@ -796,18 +798,34 @@ public abstract class MainSupport extends ServiceSupport { // now configure context with additional properties Properties prop = camelContext.getPropertiesComponent().loadProperties(); Map<String, Object> properties = new LinkedHashMap<>(); + Map<String, Object> hystrixProperties = new LinkedHashMap<>(); for (String key : prop.stringPropertyNames()) { if (key.startsWith("camel.context.")) { // grab the value String value = prop.getProperty(key); String option = key.substring(14); properties.put(option, value); + } else if (key.startsWith("camel.hystrix.")) { + // grab the value + String value = prop.getProperty(key); + String option = key.substring(14); + hystrixProperties.put(option, value); } } if (!properties.isEmpty()) { LOG.info("Auto configuring CamelContext from loaded properties: {}", properties.size()); + setCamelProperties(camelContext, camelContext, properties, true); + } + if (!hystrixProperties.isEmpty()) { + LOG.info("Auto configuring Hystrix EIP from loaded properties: {}", hystrixProperties.size()); + ModelCamelContext model = camelContext.adapt(ModelCamelContext.class); + HystrixConfigurationDefinition hystrix = model.getHystrixConfiguration(null); + if (hystrix == null) { + hystrix = new HystrixConfigurationDefinition(); + model.setHystrixConfiguration(hystrix); + } + setCamelProperties(camelContext, hystrix, hystrixProperties, true); } - setCamelProperties(camelContext, camelContext, properties, true); } protected void autoConfigurationPropertiesComponent(CamelContext camelContext) throws Exception { @@ -857,9 +875,8 @@ public abstract class MainSupport extends ServiceSupport { if (!properties.isEmpty()) { LOG.info("Auto configuring main from loaded properties: {}", properties.size()); + setCamelProperties(camelContext, config, properties, true); } - - setCamelProperties(camelContext, config, properties, true); } protected void autoConfigurationFromProperties(CamelContext camelContext) throws Exception { diff --git a/examples/camel-example-main/src/main/resources/application.properties b/examples/camel-example-main/src/main/resources/application.properties index 8bb5863..0c96fed 100644 --- a/examples/camel-example-main/src/main/resources/application.properties +++ b/examples/camel-example-main/src/main/resources/application.properties @@ -30,6 +30,9 @@ camel.main.file-configurations=src/main/data/*.properties # here we can configure the options on the component level (and we can use dash-naming-style) camel.component.quartz2.start-delayed-seconds = 3 +# to configure Hystrix EIP (global and you need to add camel-hystrix to the classpath) +### camel.hystrix.group-key=myGroup +### camel.hystrix.execution-timeout-in-milliseconds=5000 # you can configure whether OS environment should override (=2 which is default) or as fallback (=1) ### camel.component.properties.environment-variable-mode=1