/**
* Copyright 2015 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 org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Random;
import com.hystrix.junit.HystrixRequestContextRule;
import com.netflix.hystrix.exception.HystrixBadRequestException;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import com.netflix.hystrix.HystrixCircuitBreaker.HystrixCircuitBreakerImpl;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import rx.Observable;
/**
* These tests each use a different command key to ensure that running them in parallel doesn't allow the state
* built up during a test to cause others to fail
*/
public class HystrixCircuitBreakerTest {
@Rule
public HystrixRequestContextRule ctx = new HystrixRequestContextRule();
@Before
public void init() {
for (HystrixCommandMetrics metricsInstance: HystrixCommandMetrics.getInstances()) {
metricsInstance.resetStream();
}
HystrixCommandMetrics.reset();
HystrixCircuitBreaker.Factory.reset();
Hystrix.reset();
}
/**
* A simple circuit breaker intended for unit testing of the {@link HystrixCommand} object, NOT production use.
* <p>
* This uses simple logic to 'trip' the circuit after 3 subsequent failures and doesn't recover.
*/
public static class TestCircuitBreaker implements HystrixCircuitBreaker {
final HystrixCommandMetrics metrics;
private boolean forceShortCircuit = false;
public TestCircuitBreaker() {
this.metrics = getMetrics(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter());
forceShortCircuit = false;
}
public TestCircuitBreaker(HystrixCommandKey commandKey) {
this.metrics = getMetrics(commandKey, HystrixCommandPropertiesTest.getUnitTestPropertiesSetter());
forceShortCircuit = false;
}
public TestCircuitBreaker setForceShortCircuit(boolean value) {
this.forceShortCircuit = value;
return this;
}
@Override
public boolean isOpen() {
System.out.println("metrics : " + metrics.getCommandKey().name() + " : " + metrics.getHealthCounts());
if (forceShortCircuit) {
return true;
} else {
return metrics.getHealthCounts().getErrorCount() >= 3;
}
}
@Override
public void markSuccess() {
// we don't need to do anything since we're going to permanently trip the circuit
}
@Override
public void markNonSuccess() {
}
@Override
public boolean attemptExecution() {
return !isOpen();
}
@Override
public boolean allowRequest() {
return !isOpen();
}
}
/**
* Test that if all 'marks' are successes during the test window that it does NOT trip the circuit.
* Test that if all 'marks' are failures during the test window that it trips the circuit.
*/
@Test
public void testTripCircuit() {
String key = "cmd-A";
try {
HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 1);
HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);
HystrixCommand<Boolean> cmd3 = new SuccessCommand(key, 1);
HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
cmd1.execute();
cmd2.execute();
cmd3.execute();
cmd4.execute();
// this should still allow requests as everything has been successful
Thread.sleep(100);
//assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
// fail
HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 1);
HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 1);
HystrixCommand<Boolean> cmd7 = new FailureCommand(key, 1);
HystrixCommand<Boolean> cmd8 = new FailureCommand(key, 1);
cmd5.execute();
cmd6.execute();
cmd7.execute();
cmd8.execute();
// everything has failed in the test window so we should return false now
Thread.sleep(100);
assertFalse(cb.allowRequest());
assertTrue(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Test that if the % of failures is higher than the threshold that the circuit trips.
*/
@Test
public void testTripCircuitOnFailuresAboveThreshold() {
String key = "cmd-B";
try {
HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 60);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
// success with high latency
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);
cmd4.execute();
HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 1);
cmd5.execute();
HystrixCommand<Boolean> cmd6 = new SuccessCommand(key, 1);
cmd6.execute();
HystrixCommand<Boolean> cmd7 = new FailureCommand(key, 1);
cmd7.execute();
HystrixCommand<Boolean> cmd8 = new FailureCommand(key, 1);
cmd8.execute();
// this should trip the circuit as the error percentage is above the threshold
Thread.sleep(100);
assertFalse(cb.allowRequest());
assertTrue(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Test that if the % of failures is higher than the threshold that the circuit trips.
*/
@Test
public void testCircuitDoesNotTripOnFailuresBelowThreshold() {
String key = "cmd-C";
try {
HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 60);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
// success with high latency
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);
cmd4.execute();
HystrixCommand<Boolean> cmd5 = new SuccessCommand(key, 1);
cmd5.execute();
HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 1);
cmd6.execute();
HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 1);
cmd7.execute();
HystrixCommand<Boolean> cmd8 = new FailureCommand(key, 1);
cmd8.execute();
// this should remain closed as the failure threshold is below the percentage limit
Thread.sleep(100);
System.out.println("ReqLog : " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
System.out.println("Current CircuitBreaker Status : " + cmd1.getMetrics().getHealthCounts());
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Test that if all 'marks' are timeouts that it will trip the circuit.
*/
@Test
public void testTripCircuitOnTimeouts() {
String key = "cmd-D";
try {
HystrixCommand<Boolean> cmd1 = new TimeoutCommand(key);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
// success with high latency
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new TimeoutCommand(key);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new TimeoutCommand(key);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new TimeoutCommand(key);
cmd4.execute();
// everything has been a timeout so we should not allow any requests
Thread.sleep(100);
assertFalse(cb.allowRequest());
assertTrue(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Test that if the % of timeouts is higher than the threshold that the circuit trips.
*/
@Test
public void testTripCircuitOnTimeoutsAboveThreshold() {
String key = "cmd-E";
try {
HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 60);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
// success with high latency
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new TimeoutCommand(key);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);
cmd4.execute();
HystrixCommand<Boolean> cmd5 = new TimeoutCommand(key);
cmd5.execute();
HystrixCommand<Boolean> cmd6 = new TimeoutCommand(key);
cmd6.execute();
HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 1);
cmd7.execute();
HystrixCommand<Boolean> cmd8 = new TimeoutCommand(key);
cmd8.execute();
HystrixCommand<Boolean> cmd9 = new TimeoutCommand(key);
cmd9.execute();
// this should trip the circuit as the error percentage is above the threshold
Thread.sleep(100);
assertTrue(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Test that on an open circuit that a single attempt will be allowed after a window of time to see if issues are resolved.
*/
@Test
public void testSingleTestOnOpenCircuitAfterTimeWindow() {
String key = "cmd-F";
try {
int sleepWindow = 200;
HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 60);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new FailureCommand(key, 1);
cmd4.execute();
// everything has failed in the test window so we should return false now
Thread.sleep(100);
assertFalse(cb.allowRequest());
assertTrue(cb.isOpen());
// wait for sleepWindow to pass
Thread.sleep(sleepWindow + 50);
// we should now allow 1 request
assertTrue(cb.attemptExecution());
// but the circuit should still be open
assertTrue(cb.isOpen());
// and further requests are still blocked
assertFalse(cb.attemptExecution());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Test that an open circuit is closed after 1 success. This also ensures that the rolling window (containing failures) is cleared after the sleep window
* Otherwise, the next bucket roll would produce another signal to fail unless it is explicitly cleared (via {@link HystrixCommandMetrics#resetStream()}.
*/
@Test
public void testCircuitClosedAfterSuccess() {
String key = "cmd-G";
try {
int sleepWindow = 100;
HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 1, sleepWindow);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1, sleepWindow);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1, sleepWindow);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new TimeoutCommand(key, sleepWindow);
cmd4.execute();
// everything has failed in the test window so we should return false now
Thread.sleep(100);
System.out.println("ReqLog : " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
System.out.println("CircuitBreaker state 1 : " + cmd1.getMetrics().getHealthCounts());
assertTrue(cb.isOpen());
// wait for sleepWindow to pass
Thread.sleep(sleepWindow + 50);
// but the circuit should still be open
assertTrue(cb.isOpen());
// we should now allow 1 request, and upon success, should cause the circuit to be closed
HystrixCommand<Boolean> cmd5 = new SuccessCommand(key, 60, sleepWindow);
Observable<Boolean> asyncResult = cmd5.observe();
// and further requests are still blocked while the singleTest command is in flight
assertFalse(cb.allowRequest());
asyncResult.toBlocking().single();
// all requests should be open again
Thread.sleep(100);
System.out.println("CircuitBreaker state 2 : " + cmd1.getMetrics().getHealthCounts());
assertTrue(cb.allowRequest());
assertTrue(cb.allowRequest());
assertTrue(cb.allowRequest());
// and the circuit should be closed again
assertFalse(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Over a period of several 'windows' a single attempt will be made and fail and then finally succeed and close the circuit.
* <p>
* Ensure the circuit is kept open through the entire testing period and that only the single attempt in each window is made.
*/
@Test
public void testMultipleTimeWindowRetriesBeforeClosingCircuit() {
String key = "cmd-H";
try {
int sleepWindow = 200;
HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 60);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new TimeoutCommand(key);
cmd4.execute();
// everything has failed in the test window so we should return false now
System.out.println("!!!! 1: 4 failures, circuit will open on recalc");
Thread.sleep(100);
assertTrue(cb.isOpen());
// wait for sleepWindow to pass
System.out.println("!!!! 2: Sleep window starting where all commands fail-fast");
Thread.sleep(sleepWindow + 50);
System.out.println("!!!! 3: Sleep window over, should allow singleTest()");
// but the circuit should still be open
assertTrue(cb.isOpen());
// we should now allow 1 request, and upon failure, should not affect the circuit breaker, which should remain open
HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 60);
Observable<Boolean> asyncResult5 = cmd5.observe();
System.out.println("!!!! 4: Kicked off the single-test");
// and further requests are still blocked while the singleTest command is in flight
assertFalse(cb.allowRequest());
System.out.println("!!!! 5: Confirmed that no other requests go out during single-test");
asyncResult5.toBlocking().single();
System.out.println("!!!! 6: SingleTest just completed");
// all requests should still be blocked, because the singleTest failed
assertFalse(cb.allowRequest());
assertFalse(cb.allowRequest());
assertFalse(cb.allowRequest());
// wait for sleepWindow to pass
System.out.println("!!!! 2nd sleep window START");
Thread.sleep(sleepWindow + 50);
System.out.println("!!!! 2nd sleep window over");
// we should now allow 1 request, and upon failure, should not affect the circuit breaker, which should remain open
HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 60);
Observable<Boolean> asyncResult6 = cmd6.observe();
System.out.println("2nd singleTest just kicked off");
//and further requests are still blocked while the singleTest command is in flight
assertFalse(cb.allowRequest());
System.out.println("confirmed that 2nd singletest only happened once");
asyncResult6.toBlocking().single();
System.out.println("2nd singleTest now over");
// all requests should still be blocked, because the singleTest failed
assertFalse(cb.allowRequest());
assertFalse(cb.allowRequest());
assertFalse(cb.allowRequest());
// wait for sleepWindow to pass
Thread.sleep(sleepWindow + 50);
// but the circuit should still be open
assertTrue(cb.isOpen());
// we should now allow 1 request, and upon success, should cause the circuit to be closed
HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 60);
Observable<Boolean> asyncResult7 = cmd7.observe();
// and further requests are still blocked while the singleTest command is in flight
assertFalse(cb.allowRequest());
asyncResult7.toBlocking().single();
// all requests should be open again
assertTrue(cb.allowRequest());
assertTrue(cb.allowRequest());
assertTrue(cb.allowRequest());
// and the circuit should be closed again
assertFalse(cb.isOpen());
// and the circuit should be closed again
assertFalse(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* When volume of reporting during a statistical window is lower than a defined threshold the circuit
* will not trip regardless of whatever statistics are calculated.
*/
@Test
public void testLowVolumeDoesNotTripCircuit() {
String key = "cmd-I";
try {
int sleepWindow = 200;
int lowVolume = 5;
HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 60, sleepWindow, lowVolume);
HystrixCircuitBreaker cb = cmd1.circuitBreaker;
// this should start as allowing requests
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
cmd1.execute();
HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1, sleepWindow, lowVolume);
cmd2.execute();
HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1, sleepWindow, lowVolume);
cmd3.execute();
HystrixCommand<Boolean> cmd4 = new FailureCommand(key, 1, sleepWindow, lowVolume);
cmd4.execute();
// even though it has all failed we won't trip the circuit because the volume is low
Thread.sleep(100);
assertTrue(cb.allowRequest());
assertFalse(cb.isOpen());
} catch (Exception e) {
e.printStackTrace();
fail("Error occurred: " + e.getMessage());
}
}
/**
* Utility method for creating {@link HystrixCommandMetrics} for unit tests.
*/
private static HystrixCommandMetrics getMetrics(HystrixCommandProperties.Setter properties) {
return HystrixCommandMetrics.getInstance(CommandKeyForUnitTest.KEY_ONE, CommandOwnerForUnitTest.OWNER_ONE, ThreadPoolKeyForUnitTest.THREAD_POOL_ONE, HystrixCommandPropertiesTest.asMock(properties));
}
/**
* Utility method for creating {@link HystrixCommandMetrics} for unit tests.
*/
private static HystrixCommandMetrics getMetrics(HystrixCommandKey commandKey, HystrixCommandProperties.Setter properties) {
return HystrixCommandMetrics.getInstance(commandKey, CommandOwnerForUnitTest.OWNER_ONE, ThreadPoolKeyForUnitTest.THREAD_POOL_ONE, HystrixCommandPropertiesTest.asMock(properties));
}
/**
* Utility method for creating {@link HystrixCircuitBreaker} for unit tests.
*/
private static HystrixCircuitBreaker getCircuitBreaker(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandMetrics metrics, HystrixCommandProperties.Setter properties) {
return new HystrixCircuitBreakerImpl(key, commandGroup, HystrixCommandPropertiesTest.asMock(properties), metrics);
}
private static enum CommandOwnerForUnitTest implements HystrixCommandGroupKey {
OWNER_ONE, OWNER_TWO
}
private static enum ThreadPoolKeyForUnitTest implements HystrixThreadPoolKey {
THREAD_POOL_ONE, THREAD_POOL_TWO
}
private static enum CommandKeyForUnitTest implements HystrixCommandKey {
KEY_ONE, KEY_TWO
}
// ignoring since this never ends ... useful for testing https://github.com/Netflix/Hystrix/issues/236
@Ignore
@Test
public void testSuccessClosesCircuitWhenBusy() throws InterruptedException {
HystrixPlugins.getInstance().registerCommandExecutionHook(new MyHystrixCommandExecutionHook());
try {
performLoad(200, 0, 40);
performLoad(250, 100, 40);
performLoad(600, 0, 40);
} finally {
Hystrix.reset();
}
}
void performLoad(int totalNumCalls, int errPerc, int waitMillis) {
Random rnd = new Random();
for (int i = 0; i < totalNumCalls; i++) {
//System.out.println(i);
try {
boolean err = rnd.nextFloat() * 100 < errPerc;
TestCommand cmd = new TestCommand(err);
cmd.execute();
} catch (Exception e) {
//System.err.println(e.getMessage());
}
try {
Thread.sleep(waitMillis);
} catch (InterruptedException e) {
}
}
}
public class TestCommand extends HystrixCommand<String> {
boolean error;
public TestCommand(final boolean error) {
super(HystrixCommandGroupKey.Factory.asKey("group"));
this.error = error;
}
@Override
protected String run() throws Exception {
if (error) {
throw new Exception("forced failure");
} else {
return "success";
}
}
@Override
protected String getFallback() {
if (isFailedExecution()) {
return getFailedExecutionException().getMessage();
} else {
return "other fail reason";
}
}
}
private class Command extends HystrixCommand<Boolean> {
private final boolean shouldFail;
private final boolean shouldFailWithBadRequest;
private final long latencyToAdd;
public Command(String commandKey, boolean shouldFail, boolean shouldFailWithBadRequest, long latencyToAdd, int sleepWindow, int requestVolumeThreshold) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("Command")).andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)).
andCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().
withExecutionTimeoutInMilliseconds(500).
withCircuitBreakerRequestVolumeThreshold(requestVolumeThreshold).
withCircuitBreakerSleepWindowInMilliseconds(sleepWindow)));
this.shouldFail = shouldFail;
this.shouldFailWithBadRequest = shouldFailWithBadRequest;
this.latencyToAdd = latencyToAdd;
}
public Command(String commandKey, boolean shouldFail, long latencyToAdd) {
this(commandKey, shouldFail, false, latencyToAdd, 200, 1);
}
@Override
protected Boolean run() throws Exception {
Thread.sleep(latencyToAdd);
if (shouldFail) {
throw new RuntimeException("induced failure");
}
if (shouldFailWithBadRequest) {
throw new HystrixBadRequestException("bad request");
}
return true;
}
@Override
protected Boolean getFallback() {
return false;
}
}
private class SuccessCommand extends Command {
SuccessCommand(String commandKey, long latencyToAdd) {
super(commandKey, false, latencyToAdd);
}
SuccessCommand(String commandKey, long latencyToAdd, int sleepWindow) {
super(commandKey, false, false, latencyToAdd, sleepWindow, 1);
}
}
private class FailureCommand extends Command {
FailureCommand(String commandKey, long latencyToAdd) {
super(commandKey, true, latencyToAdd);
}
FailureCommand(String commandKey, long latencyToAdd, int sleepWindow) {
super(commandKey, true, false, latencyToAdd, sleepWindow, 1);
}
FailureCommand(String commandKey, long latencyToAdd, int sleepWindow, int requestVolumeThreshold) {
super(commandKey, true, false, latencyToAdd, sleepWindow, requestVolumeThreshold);
}
}
private class TimeoutCommand extends Command {
TimeoutCommand(String commandKey) {
super(commandKey, false, 2000);
}
TimeoutCommand(String commandKey, int sleepWindow) {
super(commandKey, false, false, 2000, sleepWindow, 1);
}
}
private class BadRequestCommand extends Command {
BadRequestCommand(String commandKey, long latencyToAdd) {
super(commandKey, false, true, latencyToAdd, 200, 1);
}
BadRequestCommand(String commandKey, long latencyToAdd, int sleepWindow) {
super(commandKey, false, true, latencyToAdd, sleepWindow, 1);
}
}
public class MyHystrixCommandExecutionHook extends HystrixCommandExecutionHook {
@Override
public <T> T onComplete(final HystrixInvokable<T> command, final T response) {
logHC(command, response);
return super.onComplete(command, response);
}
private int counter = 0;
private <T> void logHC(HystrixInvokable<T> command, T response) {
if(command instanceof HystrixInvokableInfo) {
HystrixInvokableInfo<T> commandInfo = (HystrixInvokableInfo<T>)command;
HystrixCommandMetrics metrics = commandInfo.getMetrics();
System.out.println("cb/error-count/%/total: "
+ commandInfo.isCircuitBreakerOpen() + " "
+ metrics.getHealthCounts().getErrorCount() + " "
+ metrics.getHealthCounts().getErrorPercentage() + " "
+ metrics.getHealthCounts().getTotalRequests() + " => " + response + " " + commandInfo.getExecutionEvents());
}
}
}
}