Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Netflix/Hystrix into iss1403
Browse files Browse the repository at this point in the history
  • Loading branch information
dmgcodevil committed Apr 16, 2017
2 parents 67fd60a + bf70168 commit 9992405
Show file tree
Hide file tree
Showing 43 changed files with 1,803 additions and 48 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,29 @@
# Hystrix Releases #

### Version 1.5.11 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.11%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.11/)) ###

- [Pull 1531](https://github.com/Netflix/Hystrix/pull/1531) Add assertion to dashboard receiving metrics data. Thanks @lholmquist !
- [Pull 1529](https://github.com/Netflix/Hystrix/pull/1529) Remove commons-collection as dependency of hystrix-javanica. Thanks @Psynbiotik !
- [Pull 1532](https://github.com/Netflix/Hystrix/pull/1532) Move metrics subscription out of synchronized block in HealthCountsStream to limit time spent holding a lock.
- [Pull 1513](https://github.com/Netflix/Hystrix/pull/1513) Fixed COMMAND_MAX_ACTIVE metrics for Coda Hale metrics. Thanks @chrisgray !
- [Pull 1515](https://github.com/Netflix/Hystrix/pull/1515) Fixed comment typo in HystrixCommand. Thanks @kmkr !
- [Pull 1512](https://github.com/Netflix/Hystrix/pull/1512) Upgrade codahale metrics-core to 3.2.2. Thanks @chrisgray !
- [Pull 1507](https://github.com/Netflix/Hystrix/pull/1507) README typo fix. Thanks @PiperChester !
- [Pull 1503](https://github.com/Netflix/Hystrix/pull/1503) Allow BadRequest exceptions to not be attached if user explicitly wants unwrapped exceptions. Thanks @mNantern !
- [Pull 1502](https://github.com/Netflix/Hystrix/pull/1502) Remove useless code in HystrixConcurrencyStrategy. Thanks @zzzvvvxxxd !
- [Pull 1495](https://github.com/Netflix/Hystrix/pull/1495) Add hystrix-metrics-event-stream-jaxrs. Thanks @justinjose28 !
- [Pull 1498](https://github.com/Netflix/Hystrix/pull/1498) Upgrade Servo to 0.10.1 in hystrix-servo-metrics-publisher

### Version 1.5.10 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.10%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.10/)) ###

- [Pull 1489](https://github.com/Netflix/Hystrix/pull/1489) Added rollingMaxConcurrentExecutionCount to CodaHale metrics publisher. Thanks @LuboVarga !
- [Pull 1481](https://github.com/Netflix/Hystrix/pull/1481) Add sanity checking to HystrixCommandAspect to debug unreproducible cases. Thanks @dmgcodevil !
- [Pull 1482](https://github.com/Netflix/Hystrix/pull/1482) Make it possible to re-use fallback methods in Javanica. (Addresses #1446). Thanks @dmgcodevil !
- [Pull 1488](https://github.com/Netflix/Hystrix/pull/1488) Fix spelling mistakes in Javanica docs. Thanks @bltb!
- [Pull 1475](https://github.com/Netflix/Hystrix/pull/1475) Added example usage of CodaHale metrics publisher. Thanks @LuboVarga !
- [Pull 1469](https://github.com/Netflix/Hystrix/pull/1469) Fix possible concurrency bug. Thanks @petercla!
- [Pull 1453](https://github.com/Netflix/Hystrix/pull/1453) Add Javanica unit test for NotWrapped checked exception. Thanks @tbvh!

### Version 1.5.9 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.9%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.9/)) ###

* [Pull 1423](https://github.com/Netflix/Hystrix/pull/1423) Write correct value to error log when maximumSize < coreSize. Thanks @diver-in-sky!
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -182,7 +182,7 @@ More information can be found on the [Dashboard Wiki](https://github.com/Netflix

## Bugs and Feedback

For bugs, questions and discussions please use the [Github Issues](https://github.com/Netflix/Hystrix/issues).
For bugs, questions and discussions please use the [GitHub Issues](https://github.com/Netflix/Hystrix/issues).


## LICENSE
Expand Down
@@ -1,6 +1,6 @@
dependencies {
compileApi project(':hystrix-core')
compileApi 'io.dropwizard.metrics:metrics-core:3.1.2'
compileApi 'io.dropwizard.metrics:metrics-core:3.2.2'
testCompile 'junit:junit-dep:4.10'
testCompile 'org.mockito:mockito-all:1.9.5'
}
Expand Up @@ -272,6 +272,13 @@ public HystrixRollingNumberEvent call() {
return HystrixRollingNumberEvent.TIMEOUT;
}
});
// the rolling number of MaxConcurrentExecutionCount. Can be used to determine saturation
safelyCreateRollingCountForEvent("rollingMaxConcurrentExecutionCount", new Func0<HystrixRollingNumberEvent>() {
@Override
public HystrixRollingNumberEvent call() {
return HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE;
}
});

// the number of executionSemaphorePermits in use right now
metricRegistry.register(createMetricName("executionSemaphorePermitsInUse"), new Gauge<Integer>() {
Expand Down
@@ -0,0 +1,46 @@
package com.netflix.hystrix.contrib.codahalemetricspublisher;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.strategy.HystrixPlugins;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.Map;

public class HystrixCodaHaleMetricsPublisherCommandTest {
private final MetricRegistry metricRegistry = new MetricRegistry();

@Before
public void setup() {
HystrixPlugins.getInstance().registerMetricsPublisher(new HystrixCodaHaleMetricsPublisher(metricRegistry));
}

@After
public void teardown() {
HystrixPlugins.reset();
}

@Test
public void commandMaxActiveGauge() {
final HystrixCommandKey hystrixCommandKey = HystrixCommandKey.Factory.asKey("test");
final HystrixCommandGroupKey hystrixCommandGroupKey = HystrixCommandGroupKey.Factory.asKey("test");

new HystrixCommand<Void>(HystrixCommand.Setter
.withGroupKey(hystrixCommandGroupKey)
.andCommandKey(hystrixCommandKey)) {
@Override
protected Void run() throws Exception {
return null;
}
}.execute();

for (Map.Entry<String, Gauge> entry : metricRegistry.getGauges().entrySet()) {
entry.getValue().getValue();
}
}
}
90 changes: 84 additions & 6 deletions hystrix-contrib/hystrix-javanica/README.md
@@ -1,7 +1,5 @@
# hystrix-javanica

**Could you please spend 5 sec and answer the [questionnaire](https://docs.google.com/forms/d/1NEeWxtL_PleX0H9GqTvKxxHqwUryJ9L048j8D3T45fs/viewform). Thank you !**

Java language has a great advantages over other languages such as reflection and annotations.
All modern frameworks such as Spring, Hibernate, myBatis and etc. seek to use this advantages to the maximum.
The idea of introduction annotations in Hystrix is obvious solution for improvement. Currently using Hystrix involves writing a lot of code that is a barrier to rapid development. You likely be spending a lot of time on writing a Hystrix commands. Idea of the Javanica project is make easier using of Hystrix by the introduction of support annotations.
Expand Down Expand Up @@ -107,7 +105,7 @@ The return type of command method should be Future that indicates that a command

## Reactive Execution

To performe "Reactive Execution" you should return an instance of `Observable` in your command method as in the example below:
To perform "Reactive Execution" you should return an instance of `Observable` in your command method as in the example below:

```java
@HystrixCommand
Expand Down Expand Up @@ -316,6 +314,86 @@ case 2: sync command, async fallback. This case isn't supported for the same rea

Same restrictions are imposed on using observable feature in javanica.

## Default fallback for class or concrete command
This feature allows to define default fallback for the whole class or concrete command. If you have a batch of commands with exactly the same fallback logic you still have to define a fallback method for every command because fallback method should have exactly the same signature as command does, consider the following code:

```java
public class Service {
@RequestMapping(value = "/test1")
@HystrixCommand(fallbackMethod = "fallback")
public APIResponse test1(String param1) {
// some codes here
return APIResponse.success("success");
}

@RequestMapping(value = "/test2")
@HystrixCommand(fallbackMethod = "fallback")
public APIResponse test2() {
// some codes here
return APIResponse.success("success");
}

@RequestMapping(value = "/test3")
@HystrixCommand(fallbackMethod = "fallback")
public APIResponse test3(ObjectRequest obj) {
// some codes here
return APIResponse.success("success");
}

private APIResponse fallback(String param1) {
return APIResponse.failed("Server is busy");
}

private APIResponse fallback() {
return APIResponse.failed("Server is busy");
}

private APIResponse fallback(ObjectRequest obj) {
return APIResponse.failed("Server is busy");
}
}
```

Default fallback feature allows to engage DRY principle and get rid of redundancy:

```java
@DefaultProperties(defaultFallback = "fallback")
public class Service {
@RequestMapping(value = "/test1")
@HystrixCommand
public APIResponse test1(String param1) {
// some codes here
return APIResponse.success("success");
}

@RequestMapping(value = "/test2")
@HystrixCommand
public APIResponse test2() {
// some codes here
return APIResponse.success("success");
}

@RequestMapping(value = "/test3")
@HystrixCommand
public APIResponse test3(ObjectRequest obj) {
// some codes here
return APIResponse.success("success");
}

private APIResponse fallback() {
return APIResponse.failed("Server is busy");
}
}
```

Default fallback method should not have any parameters except extra one to get execution exception and shouldn't throw any exceptions.
Below fallbacks listed in descending order of priority:

1. command fallback defined using `fallbackMethod` property of `@HystrixCommand`
2. command default fallback defined using `defaultFallback` property of `@HystrixCommand`
3. class default fallback defined using `defaultFallback` property of `@DefaultProperties`


## Error Propagation
Based on [this](https://github.com/Netflix/Hystrix/wiki/How-To-Use#ErrorPropagation) description, `@HystrixCommand` has an ability to specify exceptions types which should be ignored.

Expand All @@ -330,7 +408,7 @@ If `userResource.getUserById(id);` throws an exception that type is _BadRequestE

It is worth noting that by default a caller will always get the root cause exception e.g. ``BadRequestException``, never ``HystrixBadRequestException`` or ``HystrixRuntimeException`` (except the case when executed code explicitly throws those exceptions).

Optionally this exception un-wraping can be disabled for ``HystrixRuntimeException`` by using ``raiseHystrixExceptions`` i.e. all exceptions that are not ignored are raised as the _cause_ of a ``HystrixRuntimeException``:
Optionally this exception un-wrapping can be disabled for ``HystrixRuntimeException`` by using ``raiseHystrixExceptions`` i.e. all exceptions that are not ignored are raised as the _cause_ of a ``HystrixRuntimeException``:

```java
@HystrixCommand(
Expand Down Expand Up @@ -433,7 +511,7 @@ private User getUserByIdCacheKeyMethod(String id);
```
**Cache key generator**

Jacanica has only one cache key generator **HystrixCacheKeyGenerator** that generates a _HystrixGeneratedCacheKey_ based on _CacheInvocationContext_. Implementation is thread-safe.
Javanica has only one cache key generator **HystrixCacheKeyGenerator** that generates a _HystrixGeneratedCacheKey_ based on _CacheInvocationContext_. Implementation is thread-safe.
Parameters of an annotated method are selected by the following rules:
- If no parameters are annotated with _@CacheKey_ then all parameters are included
- If one or more _@CacheKey_ annotations exist only those parameters with the _@CacheKey_ annotation are included
Expand Down Expand Up @@ -709,7 +787,7 @@ To set collapser [properties](https://github.com/Netflix/Hystrix/wiki/Configurat
Read more about Hystrix request collapsing [here] (https://github.com/Netflix/Hystrix/wiki/How-it-Works#wiki-RequestCollapsing)

**Collapser error processing**
Bath command can have a fallback method.
Batch command can have a fallback method.
Example:

```java
Expand Down
1 change: 0 additions & 1 deletion hystrix-contrib/hystrix-javanica/build.gradle
Expand Up @@ -101,7 +101,6 @@ dependencies {
compile "org.aspectj:aspectjrt:$aspectjVersion"

compileApi 'com.google.guava:guava:15.0'
compile 'commons-collections:commons-collections:3.2.2'
compile 'org.apache.commons:commons-lang3:3.1'
compileApi 'com.google.code.findbugs:jsr305:2.0.0'
compile 'org.ow2.asm:asm:5.0.4'
Expand Down
Expand Up @@ -80,4 +80,13 @@
* @return exceptions to wrap
*/
HystrixException[] raiseHystrixExceptions() default {};

/**
* Specifies default fallback method for each command in the given class. Every command within the class should
* have a return type which is compatible with default fallback method return type.
* note: default fallback method cannot have parameters.
*
* @return the name of default fallback method
*/
String defaultFallback() default "";
}
Expand Up @@ -121,5 +121,14 @@
* @return exceptions to wrap
*/
HystrixException[] raiseHystrixExceptions() default {};

/**
* Specifies default fallback method for the command. If both {@link #fallbackMethod} and {@link #defaultFallback}
* methods are specified then specific one is used.
* note: default fallback method cannot have parameters, return type should be compatible with command return type.
*
* @return the name of default fallback method
*/
String defaultFallback() default "";
}

Expand Up @@ -55,6 +55,7 @@

import static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getDeclaredMethod;
import static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodFromTarget;
import static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodInfo;
import static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving;
import static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.getAjcMethodAroundAdvice;

Expand Down Expand Up @@ -283,7 +284,14 @@ private enum HystrixPointcutType {
COLLAPSER;

static HystrixPointcutType of(Method method) {
return method.isAnnotationPresent(HystrixCommand.class) ? COMMAND : COLLAPSER;
if (method.isAnnotationPresent(HystrixCommand.class)) {
return COMMAND;
} else if (method.isAnnotationPresent(HystrixCollapser.class)) {
return COLLAPSER;
} else {
String methodInfo = getMethodInfo(method);
throw new IllegalStateException("'https://github.com/Netflix/Hystrix/issues/1458' - no valid annotation found for: \n" + methodInfo);
}
}
}

Expand Down
Expand Up @@ -27,7 +27,7 @@
*/
public abstract class AsyncResult<T> implements Future<T>, ClosureCommand<T> {

private static final String ERROR_MSG = "AsyncResult is just a stab and cannot be used as complete implementation of Future";
private static final String ERROR_MSG = "AsyncResult is just a stub and cannot be used as complete implementation of Future";

@Override
public boolean cancel(boolean mayInterruptIfRunning) throws UnsupportedOperationException {
Expand Down
Expand Up @@ -105,15 +105,17 @@ private CommandAction createFallbackAction(MetaHolder metaHolder) {
if (fallbackMethod.isPresent()) {

Method fMethod = fallbackMethod.getMethod();
Object[] args = fallbackMethod.isDefault() ? new Object[0] : metaHolder.getArgs();
if (fallbackMethod.isCommand()) {
fMethod.setAccessible(true);
HystrixCommand hystrixCommand = fMethod.getAnnotation(HystrixCommand.class);
MetaHolder fmMetaHolder = MetaHolder.builder()
.obj(metaHolder.getObj())
.method(fMethod)
.ajcMethod(getAjcMethod(metaHolder.getObj(), fMethod))
.args(metaHolder.getArgs())
.args(args)
.fallback(true)
.defaultFallback(fallbackMethod.isDefault())
.defaultCollapserKey(metaHolder.getDefaultCollapserKey())
.fallbackMethod(fMethod)
.extendedFallback(fallbackMethod.isExtended())
Expand All @@ -131,12 +133,13 @@ private CommandAction createFallbackAction(MetaHolder metaHolder) {
} else {
MetaHolder fmMetaHolder = MetaHolder.builder()
.obj(metaHolder.getObj())
.defaultFallback(fallbackMethod.isDefault())
.method(fMethod)
.fallbackExecutionType(ExecutionType.SYNCHRONOUS)
.extendedFallback(fallbackMethod.isExtended())
.extendedParentFallback(metaHolder.isExtendedFallback())
.ajcMethod(null) // if fallback method isn't annotated with command annotation then we don't need to get ajc method for this
.args(metaHolder.getArgs()).build();
.args(args).build();

fallbackAction = new MethodExecutionAction(fmMetaHolder.getObj(), fMethod, fmMetaHolder.getArgs(), fmMetaHolder);
}
Expand Down
Expand Up @@ -35,6 +35,7 @@
/**
* Simple immutable holder to keep all necessary information about current method to build Hystrix command.
*/
// todo: replace fallback related flags with FallbackMethod class
@Immutable
public final class MetaHolder {

Expand All @@ -60,6 +61,7 @@ public final class MetaHolder {
private final ExecutionType fallbackExecutionType;
private final boolean fallback;
private boolean extendedParentFallback;
private final boolean defaultFallback;
private final JoinPoint joinPoint;
private final boolean observable;
private final ObservableExecutionMode observableExecutionMode;
Expand Down Expand Up @@ -93,6 +95,7 @@ private MetaHolder(Builder builder) {
this.fallbackExecutionType = builder.fallbackExecutionType;
this.joinPoint = builder.joinPoint;
this.extendedFallback = builder.extendedFallback;
this.defaultFallback = builder.defaultFallback;
this.fallback = builder.fallback;
this.extendedParentFallback = builder.extendedParentFallback;
this.observable = builder.observable;
Expand Down Expand Up @@ -227,6 +230,10 @@ public boolean isExtendedFallback() {
return extendedFallback;
}

public boolean isDefaultFallback() {
return defaultFallback;
}

@SuppressWarnings("unchecked")
public List<Class<? extends Throwable>> getCommandIgnoreExceptions() {
if (!isCommandAnnotationPresent()) return Collections.emptyList();
Expand Down Expand Up @@ -367,6 +374,7 @@ public static final class Builder {
private boolean extendedFallback;
private boolean fallback;
private boolean extendedParentFallback;
private boolean defaultFallback;
private boolean observable;
private JoinPoint joinPoint;
private ObservableExecutionMode observableExecutionMode;
Expand Down Expand Up @@ -411,6 +419,11 @@ public Builder extendedParentFallback(boolean extendedParentFallback) {
return this;
}

public Builder defaultFallback(boolean defaultFallback) {
this.defaultFallback = defaultFallback;
return this;
}

public Builder ajcMethod(Method ajcMethod) {
this.ajcMethod = ajcMethod;
return this;
Expand Down

0 comments on commit 9992405

Please sign in to comment.