com.netflix.hystrix.HystrixCommandProperties Maven / Gradle / Ivy
Show all versions of hystrix-core Show documentation
/**
* Copyright 2012 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.hystrix;
import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean;
import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger;
import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forString;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.hystrix.strategy.properties.HystrixDynamicProperty;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import com.netflix.hystrix.util.HystrixRollingNumber;
import com.netflix.hystrix.util.HystrixRollingPercentile;
/**
* Properties for instances of {@link HystrixCommand}.
*
* Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)
*/
public abstract class HystrixCommandProperties {
private static final Logger logger = LoggerFactory.getLogger(HystrixCommandProperties.class);
/* defaults */
/* package */ static final Integer default_metricsRollingStatisticalWindow = 10000;// default => statisticalWindow: 10000 = 10 seconds (and default of 10 buckets so each bucket is 1 second)
private static final Integer default_metricsRollingStatisticalWindowBuckets = 10;// default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second window so each bucket is 1 second
private static final Integer default_circuitBreakerRequestVolumeThreshold = 20;// default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds must occur before statistics matter
private static final Integer default_circuitBreakerSleepWindowInMilliseconds = 5000;// default => sleepWindow: 5000 = 5 seconds that we will sleep before trying again after tripping the circuit
private static final Integer default_circuitBreakerErrorThresholdPercentage = 50;// default => errorThresholdPercentage = 50 = if 50%+ of requests in 10 seconds are failures or latent then we will trip the circuit
private static final Boolean default_circuitBreakerForceOpen = false;// default => forceCircuitOpen = false (we want to allow traffic)
/* package */ static final Boolean default_circuitBreakerForceClosed = false;// default => ignoreErrors = false
private static final Integer default_executionTimeoutInMilliseconds = 1000; // default => executionTimeoutInMilliseconds: 1000 = 1 second
private static final Boolean default_executionTimeoutEnabled = true;
private static final ExecutionIsolationStrategy default_executionIsolationStrategy = ExecutionIsolationStrategy.THREAD;
private static final Boolean default_executionIsolationThreadInterruptOnTimeout = true;
private static final Boolean default_executionIsolationThreadInterruptOnFutureCancel = false;
private static final Boolean default_metricsRollingPercentileEnabled = true;
private static final Boolean default_requestCacheEnabled = true;
private static final Integer default_fallbackIsolationSemaphoreMaxConcurrentRequests = 10;
private static final Boolean default_fallbackEnabled = true;
private static final Integer default_executionIsolationSemaphoreMaxConcurrentRequests = 10;
private static final Boolean default_requestLogEnabled = true;
private static final Boolean default_circuitBreakerEnabled = true;
private static final Integer default_metricsRollingPercentileWindow = 60000; // default to 1 minute for RollingPercentile
private static final Integer default_metricsRollingPercentileWindowBuckets = 6; // default to 6 buckets (10 seconds each in 60 second window)
private static final Integer default_metricsRollingPercentileBucketSize = 100; // default to 100 values max per bucket
private static final Integer default_metricsHealthSnapshotIntervalInMilliseconds = 500; // default to 500ms as max frequency between allowing snapshots of health (error percentage etc)
@SuppressWarnings("unused") private final HystrixCommandKey key;
private final HystrixProperty circuitBreakerRequestVolumeThreshold; // number of requests that must be made within a statisticalWindow before open/close decisions are made using stats
private final HystrixProperty circuitBreakerSleepWindowInMilliseconds; // milliseconds after tripping circuit before allowing retry
private final HystrixProperty circuitBreakerEnabled; // Whether circuit breaker should be enabled.
private final HystrixProperty circuitBreakerErrorThresholdPercentage; // % of 'marks' that must be failed to trip the circuit
private final HystrixProperty circuitBreakerForceOpen; // a property to allow forcing the circuit open (stopping all requests)
private final HystrixProperty circuitBreakerForceClosed; // a property to allow ignoring errors and therefore never trip 'open' (ie. allow all traffic through)
private final HystrixProperty executionIsolationStrategy; // Whether a command should be executed in a separate thread or not.
private final HystrixProperty executionTimeoutInMilliseconds; // Timeout value in milliseconds for a command
private final HystrixProperty executionTimeoutEnabled; //Whether timeout should be triggered
private final HystrixProperty executionIsolationThreadPoolKeyOverride; // What thread-pool this command should run in (if running on a separate thread).
private final HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests; // Number of permits for execution semaphore
private final HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests; // Number of permits for fallback semaphore
private final HystrixProperty fallbackEnabled; // Whether fallback should be attempted.
private final HystrixProperty executionIsolationThreadInterruptOnTimeout; // Whether an underlying Future/Thread (when runInSeparateThread == true) should be interrupted after a timeout
private final HystrixProperty executionIsolationThreadInterruptOnFutureCancel; // Whether canceling an underlying Future/Thread (when runInSeparateThread == true) should interrupt the execution thread
private final HystrixProperty metricsRollingStatisticalWindowInMilliseconds; // milliseconds back that will be tracked
private final HystrixProperty metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow
private final HystrixProperty metricsRollingPercentileEnabled; // Whether monitoring should be enabled (SLA and Tracers).
private final HystrixProperty metricsRollingPercentileWindowInMilliseconds; // number of milliseconds that will be tracked in RollingPercentile
private final HystrixProperty metricsRollingPercentileWindowBuckets; // number of buckets percentileWindow will be divided into
private final HystrixProperty metricsRollingPercentileBucketSize; // how many values will be stored in each percentileWindowBucket
private final HystrixProperty metricsHealthSnapshotIntervalInMilliseconds; // time between health snapshots
private final HystrixProperty requestLogEnabled; // whether command request logging is enabled.
private final HystrixProperty requestCacheEnabled; // Whether request caching is enabled.
/**
* Isolation strategy to use when executing a {@link HystrixCommand}.
*
*
* - THREAD: Execute the {@link HystrixCommand#run()} method on a separate thread and restrict concurrent executions using the thread-pool size.
* - SEMAPHORE: Execute the {@link HystrixCommand#run()} method on the calling thread and restrict concurrent executions using the semaphore permit count.
*
*/
public static enum ExecutionIsolationStrategy {
THREAD, SEMAPHORE
}
protected HystrixCommandProperties(HystrixCommandKey key) {
this(key, new Setter(), "hystrix");
}
protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder) {
this(key, builder, "hystrix");
}
// known that we're using deprecated HystrixPropertiesChainedServoProperty until ChainedDynamicProperty exists in Archaius
protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {
this.key = key;
this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);
this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, "circuitBreaker.requestVolumeThreshold", builder.getCircuitBreakerRequestVolumeThreshold(), default_circuitBreakerRequestVolumeThreshold);
this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, "circuitBreaker.sleepWindowInMilliseconds", builder.getCircuitBreakerSleepWindowInMilliseconds(), default_circuitBreakerSleepWindowInMilliseconds);
this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, key, "circuitBreaker.errorThresholdPercentage", builder.getCircuitBreakerErrorThresholdPercentage(), default_circuitBreakerErrorThresholdPercentage);
this.circuitBreakerForceOpen = getProperty(propertyPrefix, key, "circuitBreaker.forceOpen", builder.getCircuitBreakerForceOpen(), default_circuitBreakerForceOpen);
this.circuitBreakerForceClosed = getProperty(propertyPrefix, key, "circuitBreaker.forceClosed", builder.getCircuitBreakerForceClosed(), default_circuitBreakerForceClosed);
this.executionIsolationStrategy = getProperty(propertyPrefix, key, "execution.isolation.strategy", builder.getExecutionIsolationStrategy(), default_executionIsolationStrategy);
//this property name is now misleading. //TODO figure out a good way to deprecate this property name
this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, key, "execution.isolation.thread.timeoutInMilliseconds", builder.getExecutionIsolationThreadTimeoutInMilliseconds(), default_executionTimeoutInMilliseconds);
this.executionTimeoutEnabled = getProperty(propertyPrefix, key, "execution.timeout.enabled", builder.getExecutionTimeoutEnabled(), default_executionTimeoutEnabled);
this.executionIsolationThreadInterruptOnTimeout = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnTimeout", builder.getExecutionIsolationThreadInterruptOnTimeout(), default_executionIsolationThreadInterruptOnTimeout);
this.executionIsolationThreadInterruptOnFutureCancel = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnFutureCancel", builder.getExecutionIsolationThreadInterruptOnFutureCancel(), default_executionIsolationThreadInterruptOnFutureCancel);
this.executionIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "execution.isolation.semaphore.maxConcurrentRequests", builder.getExecutionIsolationSemaphoreMaxConcurrentRequests(), default_executionIsolationSemaphoreMaxConcurrentRequests);
this.fallbackIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "fallback.isolation.semaphore.maxConcurrentRequests", builder.getFallbackIsolationSemaphoreMaxConcurrentRequests(), default_fallbackIsolationSemaphoreMaxConcurrentRequests);
this.fallbackEnabled = getProperty(propertyPrefix, key, "fallback.enabled", builder.getFallbackEnabled(), default_fallbackEnabled);
this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingStats.timeInMilliseconds", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_metricsRollingStatisticalWindow);
this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingStats.numBuckets", builder.getMetricsRollingStatisticalWindowBuckets(), default_metricsRollingStatisticalWindowBuckets);
this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, key, "metrics.rollingPercentile.enabled", builder.getMetricsRollingPercentileEnabled(), default_metricsRollingPercentileEnabled);
this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingPercentile.timeInMilliseconds", builder.getMetricsRollingPercentileWindowInMilliseconds(), default_metricsRollingPercentileWindow);
this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingPercentile.numBuckets", builder.getMetricsRollingPercentileWindowBuckets(), default_metricsRollingPercentileWindowBuckets);
this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, key, "metrics.rollingPercentile.bucketSize", builder.getMetricsRollingPercentileBucketSize(), default_metricsRollingPercentileBucketSize);
this.metricsHealthSnapshotIntervalInMilliseconds = getProperty(propertyPrefix, key, "metrics.healthSnapshot.intervalInMilliseconds", builder.getMetricsHealthSnapshotIntervalInMilliseconds(), default_metricsHealthSnapshotIntervalInMilliseconds);
this.requestCacheEnabled = getProperty(propertyPrefix, key, "requestCache.enabled", builder.getRequestCacheEnabled(), default_requestCacheEnabled);
this.requestLogEnabled = getProperty(propertyPrefix, key, "requestLog.enabled", builder.getRequestLogEnabled(), default_requestLogEnabled);
// threadpool doesn't have a global override, only instance level makes sense
this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();
}
/**
* Whether to use a {@link HystrixCircuitBreaker} or not. If false no circuit-breaker logic will be used and all requests permitted.
*
* This is similar in effect to {@link #circuitBreakerForceClosed()} except that continues tracking metrics and knowing whether it
* should be open/closed, this property results in not even instantiating a circuit-breaker.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty circuitBreakerEnabled() {
return circuitBreakerEnabled;
}
/**
* Error percentage threshold (as whole number such as 50) at which point the circuit breaker will trip open and reject requests.
*
* It will stay tripped for the duration defined in {@link #circuitBreakerSleepWindowInMilliseconds()};
*
* The error percentage this is compared against comes from {@link HystrixCommandMetrics#getHealthCounts()}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty circuitBreakerErrorThresholdPercentage() {
return circuitBreakerErrorThresholdPercentage;
}
/**
* If true the {@link HystrixCircuitBreaker#allowRequest()} will always return true to allow requests regardless of the error percentage from {@link HystrixCommandMetrics#getHealthCounts()}.
*
* The {@link #circuitBreakerForceOpen()} property takes precedence so if it set to true this property does nothing.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty circuitBreakerForceClosed() {
return circuitBreakerForceClosed;
}
/**
* If true the {@link HystrixCircuitBreaker#allowRequest()} will always return false, causing the circuit to be open (tripped) and reject all requests.
*
* This property takes precedence over {@link #circuitBreakerForceClosed()};
*
* @return {@code HystrixProperty}
*/
public HystrixProperty circuitBreakerForceOpen() {
return circuitBreakerForceOpen;
}
/**
* Minimum number of requests in the {@link #metricsRollingStatisticalWindowInMilliseconds()} that must exist before the {@link HystrixCircuitBreaker} will trip.
*
* If below this number the circuit will not trip regardless of error percentage.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty circuitBreakerRequestVolumeThreshold() {
return circuitBreakerRequestVolumeThreshold;
}
/**
* The time in milliseconds after a {@link HystrixCircuitBreaker} trips open that it should wait before trying requests again.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty circuitBreakerSleepWindowInMilliseconds() {
return circuitBreakerSleepWindowInMilliseconds;
}
/**
* Number of concurrent requests permitted to {@link HystrixCommand#run()}. Requests beyond the concurrent limit will be rejected.
*
* Applicable only when {@link #executionIsolationStrategy()} == SEMAPHORE.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests() {
return executionIsolationSemaphoreMaxConcurrentRequests;
}
/**
* What isolation strategy {@link HystrixCommand#run()} will be executed with.
*
* If {@link ExecutionIsolationStrategy#THREAD} then it will be executed on a separate thread and concurrent requests limited by the number of threads in the thread-pool.
*
* If {@link ExecutionIsolationStrategy#SEMAPHORE} then it will be executed on the calling thread and concurrent requests limited by the semaphore count.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty executionIsolationStrategy() {
return executionIsolationStrategy;
}
/**
* Whether the execution thread should attempt an interrupt (using {@link Future#cancel}) when a thread times out.
*
* Applicable only when {@link #executionIsolationStrategy()} == THREAD.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty executionIsolationThreadInterruptOnTimeout() {
return executionIsolationThreadInterruptOnTimeout;
}
/**
* Whether the execution thread should be interrupted if the execution observable is unsubscribed or the future is cancelled via {@link Future#cancel(true)}).
*
* Applicable only when {@link #executionIsolationStrategy()} == THREAD.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty executionIsolationThreadInterruptOnFutureCancel() {
return executionIsolationThreadInterruptOnFutureCancel;
}
/**
* Allow a dynamic override of the {@link HystrixThreadPoolKey} that will dynamically change which {@link HystrixThreadPool} a {@link HystrixCommand} executes on.
*
* Typically this should return NULL which will cause it to use the {@link HystrixThreadPoolKey} injected into a {@link HystrixCommand} or derived from the {@link HystrixCommandGroupKey}.
*
* When set the injected or derived values will be ignored and a new {@link HystrixThreadPool} created (if necessary) and the {@link HystrixCommand} will begin using the newly defined pool.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty executionIsolationThreadPoolKeyOverride() {
return executionIsolationThreadPoolKeyOverride;
}
/**
*
* @deprecated As of release 1.4.0, replaced by {@link #executionTimeoutInMilliseconds()}. Timeout is no longer specific to thread-isolation commands, so the thread-specific name is misleading.
*
* Time in milliseconds at which point the command will timeout and halt execution.
*
* If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted.
* If the command is semaphore-isolated and a {@link HystrixObservableCommand}, that command will get unsubscribed.
*
*
* @return {@code HystrixProperty}
*/
@Deprecated //prefer {@link #executionTimeoutInMilliseconds}
public HystrixProperty executionIsolationThreadTimeoutInMilliseconds() {
return executionTimeoutInMilliseconds;
}
/**
* Time in milliseconds at which point the command will timeout and halt execution.
*
* If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted.
* If the command is semaphore-isolated and a {@link HystrixObservableCommand}, that command will get unsubscribed.
*
*
* @return {@code HystrixProperty}
*/
public HystrixProperty executionTimeoutInMilliseconds() {
/**
* Calling a deprecated method here is a temporary workaround. We do this because {@link #executionTimeoutInMilliseconds()} is a new method (as of 1.4.0-rc.7) and an extending
* class will not have this method. It will have {@link #executionIsolationThreadTimeoutInMilliseconds()}, however.
* So, to stay compatible with an extension, we perform this redirect.
*/
return executionIsolationThreadTimeoutInMilliseconds();
}
/**
* Whether the timeout mechanism is enabled for this command
*
* @return {@code HystrixProperty}
*
* @since 1.4.4
*/
public HystrixProperty executionTimeoutEnabled() {
return executionTimeoutEnabled;
}
/**
* Number of concurrent requests permitted to {@link HystrixCommand#getFallback()}. Requests beyond the concurrent limit will fail-fast and not attempt retrieving a fallback.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests() {
return fallbackIsolationSemaphoreMaxConcurrentRequests;
}
/**
* Whether {@link HystrixCommand#getFallback()} should be attempted when failure occurs.
*
* @return {@code HystrixProperty}
*
* @since 1.2
*/
public HystrixProperty fallbackEnabled() {
return fallbackEnabled;
}
/**
* Time in milliseconds to wait between allowing health snapshots to be taken that calculate success and error percentages and affect {@link HystrixCircuitBreaker#isOpen()} status.
*
* On high-volume circuits the continual calculation of error percentage can become CPU intensive thus this controls how often it is calculated.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsHealthSnapshotIntervalInMilliseconds() {
return metricsHealthSnapshotIntervalInMilliseconds;
}
/**
* Maximum number of values stored in each bucket of the rolling percentile. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingPercentileBucketSize() {
return metricsRollingPercentileBucketSize;
}
/**
* Whether percentile metrics should be captured using {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingPercentileEnabled() {
return metricsRollingPercentileEnabled;
}
/**
* Duration of percentile rolling window in milliseconds. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
* @deprecated Use {@link #metricsRollingPercentileWindowInMilliseconds()}
*/
public HystrixProperty metricsRollingPercentileWindow() {
return metricsRollingPercentileWindowInMilliseconds;
}
/**
* Duration of percentile rolling window in milliseconds. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingPercentileWindowInMilliseconds() {
return metricsRollingPercentileWindowInMilliseconds;
}
/**
* Number of buckets the rolling percentile window is broken into. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingPercentileWindowBuckets() {
return metricsRollingPercentileWindowBuckets;
}
/**
* Duration of statistical rolling window in milliseconds. This is passed into {@link HystrixRollingNumber} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingStatisticalWindowInMilliseconds() {
return metricsRollingStatisticalWindowInMilliseconds;
}
/**
* Number of buckets the rolling statistical window is broken into. This is passed into {@link HystrixRollingNumber} inside {@link HystrixCommandMetrics}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty metricsRollingStatisticalWindowBuckets() {
return metricsRollingStatisticalWindowBuckets;
}
/**
* Whether {@link HystrixCommand#getCacheKey()} should be used with {@link HystrixRequestCache} to provide de-duplication functionality via request-scoped caching.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty requestCacheEnabled() {
return requestCacheEnabled;
}
/**
* Whether {@link HystrixCommand} execution and events should be logged to {@link HystrixRequestLog}.
*
* @return {@code HystrixProperty}
*/
public HystrixProperty requestLogEnabled() {
return requestLogEnabled;
}
private static HystrixProperty getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, Boolean builderOverrideValue, Boolean defaultValue) {
return forBoolean()
.add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, builderOverrideValue)
.add(propertyPrefix + ".command.default." + instanceProperty, defaultValue)
.build();
}
private static HystrixProperty getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, Integer builderOverrideValue, Integer defaultValue) {
return forInteger()
.add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, builderOverrideValue)
.add(propertyPrefix + ".command.default." + instanceProperty, defaultValue)
.build();
}
@SuppressWarnings("unused")
private static HystrixProperty getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, String builderOverrideValue, String defaultValue) {
return forString()
.add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, builderOverrideValue)
.add(propertyPrefix + ".command.default." + instanceProperty, defaultValue)
.build();
}
private static HystrixProperty getProperty(final String propertyPrefix, final HystrixCommandKey key, final String instanceProperty, final ExecutionIsolationStrategy builderOverrideValue, final ExecutionIsolationStrategy defaultValue) {
return new ExecutionIsolationStrategyHystrixProperty(builderOverrideValue, key, propertyPrefix, defaultValue, instanceProperty);
}
/**
* HystrixProperty that converts a String to ExecutionIsolationStrategy so we remain TypeSafe.
*/
private static final class ExecutionIsolationStrategyHystrixProperty implements HystrixProperty {
private final HystrixDynamicProperty property;
private volatile ExecutionIsolationStrategy value;
private final ExecutionIsolationStrategy defaultValue;
private ExecutionIsolationStrategyHystrixProperty(ExecutionIsolationStrategy builderOverrideValue, HystrixCommandKey key, String propertyPrefix, ExecutionIsolationStrategy defaultValue, String instanceProperty) {
this.defaultValue = defaultValue;
String overrideValue = null;
if (builderOverrideValue != null) {
overrideValue = builderOverrideValue.name();
}
property = forString()
.add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, overrideValue)
.add(propertyPrefix + ".command.default." + instanceProperty, defaultValue.name())
.build();
// initialize the enum value from the property
parseProperty();
// use a callback to handle changes so we only handle the parse cost on updates rather than every fetch
property.addCallback(new Runnable() {
@Override
public void run() {
// when the property value changes we'll update the value
parseProperty();
}
});
}
@Override
public ExecutionIsolationStrategy get() {
return value;
}
private void parseProperty() {
try {
value = ExecutionIsolationStrategy.valueOf(property.get());
} catch (Exception e) {
logger.error("Unable to derive ExecutionIsolationStrategy from property value: " + property.get(), e);
// use the default value
value = defaultValue;
}
}
}
/**
* 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 HystrixCommand} constructor to inject instance specific property overrides.
*
* See {@link HystrixPropertiesStrategy} for more information on order of precedence.
*
* Example:
*
*
{@code
* HystrixCommandProperties.Setter()
* .withExecutionTimeoutInMilliseconds(100)
* .withExecuteCommandOnSeparateThread(true);
* }
*
* @NotThreadSafe
*/
public static class Setter {
private Boolean circuitBreakerEnabled = null;
private Integer circuitBreakerErrorThresholdPercentage = null;
private Boolean circuitBreakerForceClosed = null;
private Boolean circuitBreakerForceOpen = null;
private Integer circuitBreakerRequestVolumeThreshold = null;
private Integer circuitBreakerSleepWindowInMilliseconds = null;
private Integer executionIsolationSemaphoreMaxConcurrentRequests = null;
private ExecutionIsolationStrategy executionIsolationStrategy = null;
private Boolean executionIsolationThreadInterruptOnTimeout = null;
private Boolean executionIsolationThreadInterruptOnFutureCancel = null;
private Integer executionTimeoutInMilliseconds = null;
private Boolean executionTimeoutEnabled = null;
private Integer fallbackIsolationSemaphoreMaxConcurrentRequests = null;
private Boolean fallbackEnabled = null;
private Integer metricsHealthSnapshotIntervalInMilliseconds = null;
private Integer metricsRollingPercentileBucketSize = null;
private Boolean metricsRollingPercentileEnabled = null;
private Integer metricsRollingPercentileWindowInMilliseconds = null;
private Integer metricsRollingPercentileWindowBuckets = null;
/* null means it hasn't been overridden */
private Integer metricsRollingStatisticalWindowInMilliseconds = null;
private Integer metricsRollingStatisticalWindowBuckets = null;
private Boolean requestCacheEnabled = null;
private Boolean requestLogEnabled = null;
/* package */ Setter() {
}
public Boolean getCircuitBreakerEnabled() {
return circuitBreakerEnabled;
}
public Integer getCircuitBreakerErrorThresholdPercentage() {
return circuitBreakerErrorThresholdPercentage;
}
public Boolean getCircuitBreakerForceClosed() {
return circuitBreakerForceClosed;
}
public Boolean getCircuitBreakerForceOpen() {
return circuitBreakerForceOpen;
}
public Integer getCircuitBreakerRequestVolumeThreshold() {
return circuitBreakerRequestVolumeThreshold;
}
public Integer getCircuitBreakerSleepWindowInMilliseconds() {
return circuitBreakerSleepWindowInMilliseconds;
}
public Integer getExecutionIsolationSemaphoreMaxConcurrentRequests() {
return executionIsolationSemaphoreMaxConcurrentRequests;
}
public ExecutionIsolationStrategy getExecutionIsolationStrategy() {
return executionIsolationStrategy;
}
public Boolean getExecutionIsolationThreadInterruptOnTimeout() {
return executionIsolationThreadInterruptOnTimeout;
}
public Boolean getExecutionIsolationThreadInterruptOnFutureCancel() {
return executionIsolationThreadInterruptOnFutureCancel;
}
/**
* @deprecated As of 1.4.0, use {@link #getExecutionTimeoutInMilliseconds()}
*/
@Deprecated
public Integer getExecutionIsolationThreadTimeoutInMilliseconds() {
return executionTimeoutInMilliseconds;
}
public Integer getExecutionTimeoutInMilliseconds() {
return executionTimeoutInMilliseconds;
}
public Boolean getExecutionTimeoutEnabled() {
return executionTimeoutEnabled;
}
public Integer getFallbackIsolationSemaphoreMaxConcurrentRequests() {
return fallbackIsolationSemaphoreMaxConcurrentRequests;
}
public Boolean getFallbackEnabled() {
return fallbackEnabled;
}
public Integer getMetricsHealthSnapshotIntervalInMilliseconds() {
return metricsHealthSnapshotIntervalInMilliseconds;
}
public Integer getMetricsRollingPercentileBucketSize() {
return metricsRollingPercentileBucketSize;
}
public Boolean getMetricsRollingPercentileEnabled() {
return metricsRollingPercentileEnabled;
}
public Integer getMetricsRollingPercentileWindowInMilliseconds() {
return metricsRollingPercentileWindowInMilliseconds;
}
public Integer getMetricsRollingPercentileWindowBuckets() {
return metricsRollingPercentileWindowBuckets;
}
public Integer getMetricsRollingStatisticalWindowInMilliseconds() {
return metricsRollingStatisticalWindowInMilliseconds;
}
public Integer getMetricsRollingStatisticalWindowBuckets() {
return metricsRollingStatisticalWindowBuckets;
}
public Boolean getRequestCacheEnabled() {
return requestCacheEnabled;
}
public Boolean getRequestLogEnabled() {
return requestLogEnabled;
}
public Setter withCircuitBreakerEnabled(boolean value) {
this.circuitBreakerEnabled = value;
return this;
}
public Setter withCircuitBreakerErrorThresholdPercentage(int value) {
this.circuitBreakerErrorThresholdPercentage = value;
return this;
}
public Setter withCircuitBreakerForceClosed(boolean value) {
this.circuitBreakerForceClosed = value;
return this;
}
public Setter withCircuitBreakerForceOpen(boolean value) {
this.circuitBreakerForceOpen = value;
return this;
}
public Setter withCircuitBreakerRequestVolumeThreshold(int value) {
this.circuitBreakerRequestVolumeThreshold = value;
return this;
}
public Setter withCircuitBreakerSleepWindowInMilliseconds(int value) {
this.circuitBreakerSleepWindowInMilliseconds = value;
return this;
}
public Setter withExecutionIsolationSemaphoreMaxConcurrentRequests(int value) {
this.executionIsolationSemaphoreMaxConcurrentRequests = value;
return this;
}
public Setter withExecutionIsolationStrategy(ExecutionIsolationStrategy value) {
this.executionIsolationStrategy = value;
return this;
}
public Setter withExecutionIsolationThreadInterruptOnTimeout(boolean value) {
this.executionIsolationThreadInterruptOnTimeout = value;
return this;
}
public Setter withExecutionIsolationThreadInterruptOnFutureCancel(boolean value) {
this.executionIsolationThreadInterruptOnFutureCancel = value;
return this;
}
/**
* @deprecated As of 1.4.0, replaced with {@link #withExecutionTimeoutInMilliseconds(int)}. Timeouts are no longer applied only to thread-isolated commands, so a thread-specific name is misleading
*/
@Deprecated
public Setter withExecutionIsolationThreadTimeoutInMilliseconds(int value) {
this.executionTimeoutInMilliseconds = value;
return this;
}
public Setter withExecutionTimeoutInMilliseconds(int value) {
this.executionTimeoutInMilliseconds = value;
return this;
}
public Setter withExecutionTimeoutEnabled(boolean value) {
this.executionTimeoutEnabled = value;
return this;
}
public Setter withFallbackIsolationSemaphoreMaxConcurrentRequests(int value) {
this.fallbackIsolationSemaphoreMaxConcurrentRequests = value;
return this;
}
public Setter withFallbackEnabled(boolean value) {
this.fallbackEnabled = value;
return this;
}
public Setter withMetricsHealthSnapshotIntervalInMilliseconds(int value) {
this.metricsHealthSnapshotIntervalInMilliseconds = value;
return this;
}
public Setter withMetricsRollingPercentileBucketSize(int value) {
this.metricsRollingPercentileBucketSize = value;
return this;
}
public Setter withMetricsRollingPercentileEnabled(boolean value) {
this.metricsRollingPercentileEnabled = value;
return this;
}
public Setter withMetricsRollingPercentileWindowInMilliseconds(int value) {
this.metricsRollingPercentileWindowInMilliseconds = value;
return this;
}
public Setter withMetricsRollingPercentileWindowBuckets(int value) {
this.metricsRollingPercentileWindowBuckets = value;
return this;
}
public Setter withMetricsRollingStatisticalWindowInMilliseconds(int value) {
this.metricsRollingStatisticalWindowInMilliseconds = value;
return this;
}
public Setter withMetricsRollingStatisticalWindowBuckets(int value) {
this.metricsRollingStatisticalWindowBuckets = value;
return this;
}
public Setter withRequestCacheEnabled(boolean value) {
this.requestCacheEnabled = value;
return this;
}
public Setter withRequestLogEnabled(boolean value) {
this.requestLogEnabled = value;
return this;
}
}
}