Skip to content

Commit 61b77c3

Browse files
author
Matt Jacobs
committed
Moved call to HystrixCommandExecutionHook.onComplete from completion of executeCommand() to successful executeCommand()
* It was getting called 2x in the case where run() threw an Exception
1 parent a5e52a6 commit 61b77c3

2 files changed

Lines changed: 51 additions & 11 deletions

File tree

hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,8 +1020,7 @@ public void call(final Subscriber<? super R> observer) {
10201020
@Override
10211021
public void run() {
10221022
try {
1023-
R v = originalCommand.getFallbackOrThrowException(HystrixEventType.TIMEOUT, FailureType.TIMEOUT, "timed-out", new TimeoutException());
1024-
observer.onNext(v);
1023+
observer.onNext(originalCommand.getFallbackOrThrowException(HystrixEventType.TIMEOUT, FailureType.TIMEOUT, "timed-out", new TimeoutException()));
10251024
observer.onCompleted();
10261025
} catch (HystrixRuntimeException re) {
10271026
observer.onError(re);
@@ -1113,7 +1112,6 @@ private Subscription subscribeWithSemaphoreIsolation(final Observer<? super R> o
11131112

11141113
// execute outside of future so that fireAndForget will still work (ie. someone calls queue() but not get()) and so that multiple requests can be deduped through request caching
11151114
R r = executeCommand();
1116-
r = executionHook.onComplete(this, r);
11171115
observer.onNext(r);
11181116
/* execution time (must occur before terminal state otherwise a race condition can occur if requested by client) */
11191117
recordTotalExecutionTime(invocationStartTime);
@@ -1186,8 +1184,6 @@ public R call() throws Exception {
11861184
R r = executeCommand();
11871185
// if we can go from NOT_EXECUTED to COMPLETED then we did not timeout
11881186
if (isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.COMPLETED)) {
1189-
// give the hook an opportunity to modify it
1190-
r = executionHook.onComplete(_this, r);
11911187
// pass to the observer
11921188
observer.onNext(r);
11931189
// state changes before termination
@@ -1292,7 +1288,7 @@ private R executeCommand() {
12921288
metrics.markSuccess(duration);
12931289
circuitBreaker.markSuccess();
12941290
eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) duration, executionResult.events);
1295-
return response;
1291+
return executionHook.onComplete(this, response);
12961292
}
12971293
} catch (HystrixBadRequestException e) {
12981294
try {
@@ -1643,7 +1639,6 @@ private R getFallbackOrThrowException(HystrixEventType eventType, FailureType fa
16431639
metrics.markFallbackSuccess();
16441640
// record the executionResult
16451641
executionResult = executionResult.addEvents(HystrixEventType.FALLBACK_SUCCESS);
1646-
16471642
return executionHook.onComplete(this, fallback);
16481643
} catch (UnsupportedOperationException fe) {
16491644
logger.debug("No fallback for HystrixCommand. ", fe); // debug only since we're throwing the exception and someone higher will do something with it
@@ -5657,7 +5652,7 @@ public void testExecutionHookRunFailureWithFallback() {
56575652
assertEquals(1, command.builder.executionHook.threadComplete.get());
56585653

56595654
// expected hook execution sequence
5660-
assertEquals("onStart - onThreadStart - onRunStart - onRunError - onFallbackStart - onFallbackSuccess - onThreadComplete - onComplete - ", command.builder.executionHook.executionSequence.toString());
5655+
assertEquals("onStart - onThreadStart - onRunStart - onRunError - onFallbackStart - onFallbackSuccess - onComplete - onThreadComplete - ", command.builder.executionHook.executionSequence.toString());
56615656
}
56625657

56635658
/**
@@ -5902,7 +5897,52 @@ public void testExecutionHookRejectedWithFallback() {
59025897
* Execution hook on short-circuit with a fallback
59035898
*/
59045899
@Test
5905-
public void testExecutionHookShortCircuitedWithFallbackViaQueue() {
5900+
public void testExecutionHookShortCircuitedWithFallbackViaExecute() {
5901+
TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true);
5902+
KnownFailureTestCommandWithFallback command = new KnownFailureTestCommandWithFallback(circuitBreaker);
5903+
try {
5904+
// now execute one that will be short-circuited
5905+
command.execute();
5906+
} catch (Exception e) {
5907+
throw new RuntimeException("not expecting", e);
5908+
}
5909+
5910+
assertTrue(command.isResponseShortCircuited());
5911+
5912+
// the run() method should not run as we're short-circuited
5913+
assertEquals(0, command.builder.executionHook.startRun.get());
5914+
// we should not have a response because of short-circuit
5915+
assertNull(command.builder.executionHook.runSuccessResponse);
5916+
// we should not have an exception because we didn't run
5917+
assertNull(command.builder.executionHook.runFailureException);
5918+
5919+
// the fallback() method should be run due to short-circuit
5920+
assertEquals(1, command.builder.executionHook.startFallback.get());
5921+
// response since we have a fallback
5922+
assertNotNull(command.builder.executionHook.fallbackSuccessResponse);
5923+
// null since fallback succeeds
5924+
assertNull(command.builder.executionHook.fallbackFailureException);
5925+
5926+
// execution occurred
5927+
assertEquals(1, command.builder.executionHook.startExecute.get());
5928+
// we should have a response because of fallback
5929+
assertNotNull(command.builder.executionHook.endExecuteSuccessResponse);
5930+
// we should not have an exception because of fallback
5931+
assertNull(command.builder.executionHook.endExecuteFailureException);
5932+
5933+
// thread execution
5934+
assertEquals(0, command.builder.executionHook.threadStart.get());
5935+
assertEquals(0, command.builder.executionHook.threadComplete.get());
5936+
5937+
// expected hook execution sequence
5938+
assertEquals("onStart - onFallbackStart - onFallbackSuccess - onComplete - ", command.builder.executionHook.executionSequence.toString());
5939+
}
5940+
5941+
/**
5942+
* Execution hook on short-circuit without a fallback
5943+
*/
5944+
@Test
5945+
public void testExecutionHookShortCircuitedWithoutFallbackViaQueue() {
59065946
TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true);
59075947
KnownFailureTestCommandWithoutFallback command = new KnownFailureTestCommandWithoutFallback(circuitBreaker);
59085948
try {
@@ -5950,7 +5990,7 @@ public void testExecutionHookShortCircuitedWithFallbackViaQueue() {
59505990
* Execution hook on short-circuit with a fallback
59515991
*/
59525992
@Test
5953-
public void testExecutionHookShortCircuitedWithFallbackViaExecute() {
5993+
public void testExecutionHookShortCircuitedWithoutFallbackViaExecute() {
59545994
TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true);
59555995
KnownFailureTestCommandWithoutFallback command = new KnownFailureTestCommandWithoutFallback(circuitBreaker);
59565996
try {

hystrix-core/src/main/java/com/netflix/hystrix/exception/HystrixRuntimeException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class HystrixRuntimeException extends RuntimeException {
3131
private final FailureType failureCause;
3232

3333
public static enum FailureType {
34-
COMMAND_EXCEPTION, TIMEOUT, SHORTCIRCUIT, REJECTED_THREAD_EXECUTION, REJECTED_SEMAPHORE_EXECUTION, BAD_REQUEST_EXCEPTION, REJECTED_SEMAPHORE_FALLBACK
34+
BAD_REQUEST_EXCEPTION, COMMAND_EXCEPTION, TIMEOUT, SHORTCIRCUIT, REJECTED_THREAD_EXECUTION, REJECTED_SEMAPHORE_EXECUTION, REJECTED_SEMAPHORE_FALLBACK
3535
}
3636

3737
public HystrixRuntimeException(FailureType failureCause, Class<? extends HystrixCommand> commandClass, String message, Exception cause, Throwable fallbackException) {

0 commit comments

Comments
 (0)