Skip to content

Commit

Permalink
Merge pull request #326 from yuhanz/master
Browse files Browse the repository at this point in the history
Added supports for setting threadPoolProperties through @HystrixCommand annotation
  • Loading branch information
benjchristensen committed Nov 9, 2014
2 parents 62ac93f + 9acbd36 commit 020b8d9
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 2 deletions.
19 changes: 19 additions & 0 deletions hystrix-contrib/hystrix-javanica/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,25 @@ ConfigurationManager.getConfigInstance().setProperty("hystrix.command.getUserByI
```
More about Hystrix command properties [command](https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-CommandExecution) and [fallback](https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-CommandFallback)

ThreadPoolProperties can be set using @HystrixCommand's 'threadPoolProperties' like below:

```java
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "101"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
})
public User getUserById(String id) {
return userResource.getUserById(id);
}
```

## Hystrix collapser

Suppose you have some command which calls should be collapsed in one backend call. For this goal you can use ```@HystrixCollapser``` annotation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@
*/
HystrixProperty[] commandProperties() default {};

/**
* Specifies thread pool properties.
*
* @return thread pool properties
*/
HystrixProperty[] threadPoolProperties() default {};

/**
* Defines exceptions which should be ignored and wrapped to throw in HystrixBadRequestException.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@

import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

Expand Down Expand Up @@ -51,6 +54,8 @@ public T create(MetaHolder metaHolder,
metaHolder.getHystrixCommand().commandKey()
: metaHolder.getDefaultCommandKey();

HystrixPropertiesManager.initializeThreadPoolProperties(metaHolder.getHystrixCommand());

CommandSetterBuilder setterBuilder = new CommandSetterBuilder();
setterBuilder.commandKey(commandKey);
setterBuilder.groupKey(groupKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import org.apache.commons.lang3.StringUtils;

/**
Expand All @@ -29,6 +30,7 @@ public class CommandSetterBuilder {
private String groupKey;
private String commandKey;
private String threadPoolKey;
private HystrixThreadPoolProperties.Setter threadPoolProperties = null;

public CommandSetterBuilder groupKey(String pGroupKey) {
this.groupKey = pGroupKey;
Expand All @@ -50,11 +52,15 @@ public CommandSetterBuilder commandKey(String pCommandKey, String def) {
return this;
}

public CommandSetterBuilder threadPoolProperties(HystrixThreadPoolProperties.Setter threadPoolProperties) {
this.threadPoolProperties = threadPoolProperties;
return this;
}

public CommandSetterBuilder threadPoolKey(String pThreadPoolKey) {
this.threadPoolKey = pThreadPoolKey;
return this;
}

/**
* Creates instance of {@link HystrixCommand.Setter}.
*
Expand All @@ -67,6 +73,9 @@ public HystrixCommand.Setter build() {
if (StringUtils.isNotBlank(threadPoolKey)) {
setter.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey));
}
if (threadPoolProperties != null) {
setter.andThreadPoolPropertiesDefaults(threadPoolProperties);
}
return setter;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.google.common.collect.Maps;
import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
Expand Down Expand Up @@ -96,4 +97,22 @@ private static void validate(HystrixProperty hystrixProperty) throws IllegalArgu
Validate.notBlank(hystrixProperty.name(), "hystrix property name cannot be null");
}

public static void initializeThreadPoolProperties(HystrixCommand hystrixCommand) {
if(hystrixCommand.threadPoolProperties() == null || hystrixCommand.threadPoolProperties().length == 0) {
return;
}

HystrixThreadPoolProperties.Setter setter = HystrixThreadPoolProperties.Setter();
String threadPoolKey = hystrixCommand.threadPoolKey();
if(threadPoolKey == null || "".equals(threadPoolKey)) {
threadPoolKey = "default";
}

HystrixProperty[] properties = hystrixCommand.threadPoolProperties();
for(HystrixProperty property : properties) {
String name = String.format("hystrix.threadpool.%s.%s", threadPoolKey, property.name());
ConfigurationManager.getConfigInstance().setProperty(name, property.value());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import com.netflix.hystrix.HystrixEventType;
import com.netflix.hystrix.HystrixRequestLog;
import com.netflix.hystrix.HystrixThreadPool;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;
import com.netflix.hystrix.contrib.javanica.test.spring.domain.User;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -15,6 +18,9 @@
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

Expand All @@ -26,7 +32,7 @@ public class CommandPropertiesTest {
private UserService userService;

@Test
public void testGetUser() {
public void testGetUser() throws NoSuchFieldException, IllegalAccessException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
User u1 = userService.getUser("1", "name: ");
Expand All @@ -41,6 +47,21 @@ public void testGetUser() {
// assert properties
assertEquals(110, command.getProperties().executionIsolationThreadTimeoutInMilliseconds().get().intValue());
assertEquals(false, command.getProperties().executionIsolationThreadInterruptOnTimeout().get());

Field field = command.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("threadPool");
field.setAccessible(true);
HystrixThreadPool threadPool = (HystrixThreadPool) field.get(command);

Field field2 = HystrixThreadPool.HystrixThreadPoolDefault.class.getDeclaredField("properties");
field2.setAccessible(true);
HystrixThreadPoolProperties properties = (HystrixThreadPoolProperties) field2.get(threadPool);

assertEquals(30, (int) properties.coreSize().get());
assertEquals(101, (int) properties.maxQueueSize().get());
assertEquals(2, (int) properties.keepAliveTimeMinutes().get());
assertEquals(15, (int) properties.queueSizeRejectionThreshold().get());
assertEquals(1440, (int) properties.metricsRollingStatisticalWindowInMilliseconds().get());
assertEquals(12, (int) properties.metricsRollingStatisticalWindowBuckets().get());
} finally {
context.shutdown();
}
Expand Down Expand Up @@ -70,6 +91,14 @@ public static class UserService {
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "110"),
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "false")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "101"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
})
public User getUser(String id, String name) {
return new User(id, name + id); // it should be network call
Expand Down

0 comments on commit 020b8d9

Please sign in to comment.