Programmatically changing Hystrix properties

There is a very simple way of doing this. It just needs 2 steps: a. registering the right plugin b. Adding the correct strategy with the required override.

Use-case: Override ExecutionTimeoutInMilliseconds to 30000 ms from 1000 ms

HystrixPlugins.getInstance().registerPropertiesStrategy(new HystrixPropertiesStrategy() {
            @Override
            public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
                HystrixCommandProperties.Setter timeout
                        = HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(30000);
                return super.getCommandProperties(commandKey, timeout);
            }
        });

Here I am just overriding the required property. When you run your application you can see this in the DEBUG mode:

2018-06-08 23:18:32 [main] DEBUG c.n.h.s.p.HystrixPropertiesChainedProperty - Flipping property: hystrix.command.Client#getAllData().execution.isolation.thread.timeoutInMilliseconds to use its current value: 30000

Late answer, but today i struggled with the same thing and found a way.

The way the default property manager is implemented is that it uses a cache of HystrixCommandProperties based on the name of the command you run. On the first use of the command, it caches what it gets out of the HystrixCommandProperties.Setter passed to the Command's constructor and that's it.

However, using the custom HystrixPropertiesStrategy as a Plugin you can override the cache key (and hence force Hystrix to re-evaluate the Setter passed to the new Command instance, because the cache key is new, so it thinks it's a new Command).

The code would then look similar to this:

public HystrixCommandFactory(....) {
    HystrixPlugins.getInstance().registerPropertiesStrategy(new HystrixPropertiesStrategyWithReloadableCache());
    updateHystrixSettings();        
}

//configurable attributes
private volatile int commandTimeoutMillis;
private volatile long lastSettingsUpdatedTimestamp;
private volatile HystrixCommand.Setter setterForNewCommands;

private void updateHystrixSettings() {
    lastSettingsUpdatedTimestamp = LocalDateTime.now().toDateTime().getMillis();
    HystrixCommandProperties.Setter propertiesSetter = HystrixCommandProperties.Setter()
        .withExecutionTimeoutInMilliseconds(commandTimeoutMillis)
        .withExecutionTimeoutEnabled(true);

    this.setterForNewCommands = HystrixCommand.Setter
        .withGroupKey(HystrixCommandGroupKey.Factory.asKey(GROUP_NAME))
        .andCommandPropertiesDefaults(propertiesSetter);

}

public void setCommandTimeoutMillis(int commandTimeoutMillis) {     
    this.commandTimeoutMillis = commandTimeoutMillis;
    updateHystrixSettings();        
}

private class HystrixPropertiesStrategyWithReloadableCache extends HystrixPropertiesStrategy {

    @Override
    public String getCommandPropertiesCacheKey(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
        return String.format("%s-%d", commandKey.name(), lastSettingsUpdatedTimestamp);
    }
}

Alternatively, you could always return null from the getCommandPropertiesCacheKey method (that completely turns off caching), but then you have the overhead of Hystrix having to reconstruct the HystrixCommandProperties each time a Command is called

PS: Be sure to use proper thread synchronization for reading and updating these properties, because those will be called from different threads. I omitted that in this sample for simplicity, but I actually use a ReentrantReadWriteLock in my code to guard accesses to these variables


Hystrix properties can also be set in our service class inside @HystrixCommand annotation, for this we use the Hystrix-Javanica project which is used for implementing the annotations in our project. For that we need to add the dependency of hystrix-javanica into our classpath.

Dependency for Maven:

<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
    <version>x.y.z</version>
</dependency>

Inside the @HystrixCommand annotation we can use @HystrixProperty to set the properties for hystrix.

sample @HystrixCommand properties setting:

@HystrixCommand(groupKey = "StoreSubmission", commandKey = "StoreSubmission", threadPoolKey = "StoreSubmission", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "30000"),
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "4"),
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "60000"),
        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000") }, threadPoolProperties = {
        @HystrixProperty(name = "coreSize", value = "30"),
        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000") })
public String storeSubmission(ReturnType returnType, InputStream is, String id) {
}

The best way to define these properties is in externalized application.yaml, that way you can control it better & change them for different environments.

Here is the sample hystrix config in my application.yaml

hystrix:
   command.StoreSubmission.execution.isolation.thread.timeoutInMilliseconds: 30000
   command.StoreSubmission.circuitBreaker.requestVolumeThreshold: 4
   command.StoreSubmission.circuitBreaker.sleepWindowInMilliseconds: 60000
   command.StoreSubmission.metrics.rollingStats.timeInMilliseconds: 180000
   collapser.StoreSubmission.maxRequestsInBatch: 1
   collapser.StoreSubmission.requestCache.enabled: FALSE
   threadpool.StoreSubmission.coreSize: 30
   threadpool.StoreSubmission.metrics.rollingStats.timeInMilliseconds: 180000

The Exact format for the application.yml file is

hystrix:
    command:
        findAllProducts:
            execution:
                isolation:
                    thread:
                        timeoutInMilliseconds: 1000
            circuitBreaker:
                requestVolumeThreshold: 20
                errorThresholdPercentage: 50
            metrics:
                rollingStats:
                    timeInMilliseconds: 10000
                    numBuckets: 10
    threadpool:
        ProductService:
            coreSize: 10

For further information on Hystrix-Javanica visit here


For future reference: I ended up using the settings through ConfigurationManager and a string property.

ConfigurationManager.getConfigInstance().setProperty("...")

It let's me change things, but in a less type-safe way than the original code. I did struggle for some time with a typo in the string which is why I'd like to avoid that.

I now use this for all the properties I need to change runtime. Creating a new Hystrix circuit breaker every time something changes (new command key) could be an option as well, but would break using properties files later on.