diff --git a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CircuitBreakerHelper.java b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CircuitBreakerHelper.java index 8221488f0b6..f8e1eec724a 100644 --- a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CircuitBreakerHelper.java +++ b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CircuitBreakerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,10 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; -import com.netflix.hystrix.HystrixCommand; +import com.netflix.config.ConfigurationManager; import org.eclipse.microprofile.faulttolerance.CircuitBreaker; /** @@ -31,7 +32,8 @@ public class CircuitBreakerHelper { private static final Logger LOGGER = Logger.getLogger(CircuitBreakerHelper.class.getName()); - private static final long MAX_DELAY_CIRCUIT_BREAKER_OPEN = 1000; + private static final String FORCE_OPEN = "hystrix.command.%s.circuitBreaker.forceOpen"; + private static final String FORCE_CLOSED = "hystrix.command.%s.circuitBreaker.forceClosed"; /** * Internal state of a circuit breaker. We need to track this to implement @@ -67,6 +69,8 @@ static class CommandData { private long lastNanosRead; + private ReentrantLock lock = new ReentrantLock(); + CommandData(int capacity) { results = new boolean[capacity]; size = 0; @@ -74,13 +78,24 @@ static class CommandData { lastNanosRead = System.nanoTime(); } + ReentrantLock getLock() { + return lock; + } + State getState() { return state; } + long getCurrentStateNanos() { + return System.nanoTime() - lastNanosRead; + } + void setState(State newState) { if (state != newState) { updateStateNanos(state); + if (newState == State.HALF_OPEN_MP) { + successCount = 0; + } state = newState; } } @@ -166,6 +181,10 @@ private CommandData getCommandData() { * initial state, we remove it from the map and re-create it later if needed. */ void resetCommandData() { + ReentrantLock lock = getCommandData().getLock(); + if (lock.isLocked()) { + lock.unlock(); + } COMMAND_STATS.remove(command.getCommandKey().toString()); LOGGER.info("Discarded command data for " + command.getCommandKey()); } @@ -181,12 +200,12 @@ void pushResult(boolean result) { } /** - * Computes success ratio over a complete window. + * Returns nanos since switching to current state. * - * @return Success ratio or -1 if window is not complete. + * @return Nanos in state. */ - double getSuccessRatio() { - return getCommandData().getSuccessRatio(); + long getCurrentStateNanos() { + return getCommandData().getCurrentStateNanos(); } /** @@ -209,10 +228,16 @@ State getState() { /** * Changes the state of a circuit breaker. - * @param newState + * + * @param newState New state. */ void setState(State newState) { getCommandData().setState(newState); + if (newState == State.OPEN_MP) { + openBreaker(); + } else { + closeBreaker(); + } LOGGER.info("Circuit breaker for " + command.getCommandKey() + " now in state " + getState()); } @@ -233,12 +258,17 @@ void incSuccessCount() { } /** - * Returns underlying object for sync purposes only. - * - * @return Command data as an object. + * Prevent concurrent access to underlying command data. + */ + void lock() { + getCommandData().getLock().lock(); + } + + /** + * Unlock access to underlying command data. */ - Object getSyncObject() { - return getCommandData(); + void unlock() { + getCommandData().getLock().unlock(); } /** @@ -252,27 +282,24 @@ long getInStateNanos(State queryState) { } /** - * Ensure that our internal state matches Hystrix when a breaker in OPEN - * state. For some reason Hystrix does not set the breaker in OPEN state - * right away, and calling {@link HystrixCommand#isCircuitBreakerOpen()} - * appears to fix the problem. + * Force Hystrix's circuit breaker into an open state. */ - void ensureConsistentState() { - if (getState() == State.OPEN_MP) { - long delayTotal = 0L; - while (!command.isCircuitBreakerOpen() && delayTotal < MAX_DELAY_CIRCUIT_BREAKER_OPEN) { - long delayPeriod = MAX_DELAY_CIRCUIT_BREAKER_OPEN / 10; - try { - LOGGER.fine("Waiting for Hystrix to open circuit breaker (" + delayPeriod + " ms)"); - Thread.sleep(delayPeriod); - } catch (InterruptedException e) { - // falls through - } - delayTotal += delayPeriod; - } - if (delayTotal >= MAX_DELAY_CIRCUIT_BREAKER_OPEN) { - throw new InternalError("Inconsistent state for circuit breaker in " + command.getCommandKey()); - } + private void openBreaker() { + if (!command.isCircuitBreakerOpen()) { + ConfigurationManager.getConfigInstance().setProperty( + String.format(FORCE_OPEN, command.getCommandKey()), "true"); + } + } + + /** + * Force Hystrix's circuit breaker into a closed state. + */ + private void closeBreaker() { + if (command.isCircuitBreakerOpen()) { + ConfigurationManager.getConfigInstance().setProperty( + String.format(FORCE_OPEN, command.getCommandKey()), "false"); + ConfigurationManager.getConfigInstance().setProperty( + String.format(FORCE_CLOSED, command.getCommandKey()), "true"); } } } diff --git a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CommandRetrier.java b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CommandRetrier.java index ea01b26a133..c1b86244979 100644 --- a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CommandRetrier.java +++ b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CommandRetrier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -185,14 +185,16 @@ private Object retryExecute() throws Exception { if (cause instanceof HystrixRuntimeException) { cause = cause.getCause(); } + updateMetricsAfter(cause); + if (cause instanceof TimeoutException) { throw new org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException(cause); } if (cause instanceof RejectedExecutionException) { throw new BulkheadException(cause); } - if (command.isCircuitBreakerOpen()) { + if (isHystrixBreakerException(cause)) { throw new CircuitBreakerOpenException(cause); } throw toException(cause); @@ -273,4 +275,16 @@ private void updateMetricsAfter(Throwable cause) { private String createCommandKey() { return method.getName() + Objects.hash(context.getTarget(), context.getMethod().hashCode()); } + + /** + * Hystrix throws a {@code RuntimeException}, so we need to check + * the message to determine if it is a breaker exception. + * + * @param t Throwable to check. + * @return Outcome of test. + */ + private static boolean isHystrixBreakerException(Throwable t) { + return t instanceof RuntimeException && t.getMessage().contains("Hystrix " + + "circuit short-circuited and is OPEN"); + } } diff --git a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java index 36d61a73380..fe20a8b7271 100644 --- a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java +++ b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,8 @@ import org.eclipse.microprofile.metrics.Histogram; import static com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy.THREAD; + +import static io.helidon.microprofile.faulttolerance.CircuitBreakerHelper.State; import static io.helidon.microprofile.faulttolerance.FaultToleranceExtension.isFaultToleranceMetricsEnabled; import static io.helidon.microprofile.faulttolerance.FaultToleranceMetrics.BREAKER_CALLS_FAILED_TOTAL; import static io.helidon.microprofile.faulttolerance.FaultToleranceMetrics.BREAKER_CALLS_PREVENTED_TOTAL; @@ -56,7 +58,7 @@ public class FaultToleranceCommand extends HystrixCommand { private static final Logger LOGGER = Logger.getLogger(FaultToleranceCommand.class.getName()); - private static final String HELIDON_MICROPROFILE_FAULTTOLERANCE = "io.helidon.microprofile.faulttolerance"; + static final String HELIDON_MICROPROFILE_FAULTTOLERANCE = "io.helidon.microprofile.faulttolerance"; private final String commandKey; @@ -72,31 +74,6 @@ public class FaultToleranceCommand extends HystrixCommand { private long queuedNanos = -1L; - /** - * A Hystrix command that can be used to open or close a circuit breaker - * by running a succession of passing or failing commands that are part - * of a {@link Runnable}. - */ - private static class RunnableCommand extends HystrixCommand { - - private final Runnable runnable; - - RunnableCommand(String commandKey, Runnable runnable) { - super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(HELIDON_MICROPROFILE_FAULTTOLERANCE)) - .andCommandKey( - HystrixCommandKey.Factory.asKey(commandKey)) - .andCommandPropertiesDefaults( - HystrixCommandProperties.Setter().withFallbackEnabled(false))); - this.runnable = runnable; - } - - @Override - protected Object run() throws Exception { - runnable.run(); - return ""; - } - } - /** * Default thread pool size for a command or a command group. */ @@ -118,34 +95,34 @@ protected Object run() throws Exception { */ public FaultToleranceCommand(String commandKey, MethodIntrospector introspector, InvocationContext context) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(HELIDON_MICROPROFILE_FAULTTOLERANCE)) - .andCommandKey( + .andCommandKey( HystrixCommandKey.Factory.asKey(commandKey)) - .andCommandPropertiesDefaults( + .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() - .withFallbackEnabled(false) - .withExecutionIsolationStrategy(THREAD)) - .andThreadPoolKey( + .withFallbackEnabled(false) + .withExecutionIsolationStrategy(THREAD)) + .andThreadPoolKey( introspector.hasBulkhead() - ? HystrixThreadPoolKey.Factory.asKey(commandKey) - : null) - .andThreadPoolPropertiesDefaults( + ? HystrixThreadPoolKey.Factory.asKey(commandKey) + : null) + .andThreadPoolPropertiesDefaults( HystrixThreadPoolProperties.Setter() - .withCoreSize( - introspector.hasBulkhead() - ? introspector.getBulkhead().value() - : MAX_THREAD_POOL_SIZE) - .withMaximumSize( - introspector.hasBulkhead() - ? introspector.getBulkhead().value() - : MAX_THREAD_POOL_SIZE) - .withMaxQueueSize( - introspector.hasBulkhead() && introspector.isAsynchronous() - ? introspector.getBulkhead().waitingTaskQueue() - : MAX_THREAD_POOL_QUEUE_SIZE) - .withQueueSizeRejectionThreshold( - introspector.hasBulkhead() && introspector.isAsynchronous() - ? introspector.getBulkhead().waitingTaskQueue() - : MAX_THREAD_POOL_QUEUE_SIZE))); + .withCoreSize( + introspector.hasBulkhead() + ? introspector.getBulkhead().value() + : MAX_THREAD_POOL_SIZE) + .withMaximumSize( + introspector.hasBulkhead() + ? introspector.getBulkhead().value() + : MAX_THREAD_POOL_SIZE) + .withMaxQueueSize( + introspector.hasBulkhead() && introspector.isAsynchronous() + ? introspector.getBulkhead().waitingTaskQueue() + : MAX_THREAD_POOL_QUEUE_SIZE) + .withQueueSizeRejectionThreshold( + introspector.hasBulkhead() && introspector.isAsynchronous() + ? introspector.getBulkhead().waitingTaskQueue() + : MAX_THREAD_POOL_QUEUE_SIZE))); this.commandKey = commandKey; this.introspector = introspector; this.context = context; @@ -159,15 +136,15 @@ public FaultToleranceCommand(String commandKey, MethodIntrospector introspector, registerGauge(introspector.getMethod(), BREAKER_OPEN_TOTAL, "Amount of time the circuit breaker has spent in open state", - () -> breakerHelper.getInStateNanos(CircuitBreakerHelper.State.OPEN_MP)); + () -> breakerHelper.getInStateNanos(State.OPEN_MP)); registerGauge(introspector.getMethod(), BREAKER_HALF_OPEN_TOTAL, "Amount of time the circuit breaker has spent in half-open state", - () -> breakerHelper.getInStateNanos(CircuitBreakerHelper.State.HALF_OPEN_MP)); + () -> breakerHelper.getInStateNanos(State.HALF_OPEN_MP)); registerGauge(introspector.getMethod(), BREAKER_CLOSED_TOTAL, "Amount of time the circuit breaker has spent in closed state", - () -> breakerHelper.getInStateNanos(CircuitBreakerHelper.State.CLOSED_MP)); + () -> breakerHelper.getInStateNanos(State.CLOSED_MP)); } } @@ -254,123 +231,129 @@ public Object run() throws Exception { */ @Override public Object execute() { - // Configure command before execution - introspector.getHystrixProperties() + boolean lockRemoved = false; + + try { + // Configure command before execution + introspector.getHystrixProperties() .entrySet() .forEach(entry -> setProperty(entry.getKey(), entry.getValue())); - // Ensure our internal state is consistent with Hystrix - if (introspector.hasCircuitBreaker()) { - breakerHelper.ensureConsistentState(); - LOGGER.info("Enter: breaker for " + getCommandKey() + " in state " + breakerHelper.getState()); - } + // Get lock and check breaker delay + if (introspector.hasCircuitBreaker()) { + breakerHelper.lock(); // acquire exclusive access to command data - // Record state of breaker - boolean wasBreakerOpen = isCircuitBreakerOpen(); + // OPEN_MP -> HALF_OPEN_MP + if (breakerHelper.getState() == State.OPEN_MP) { + long delayNanos = TimeUtil.convertToNanos(introspector.getCircuitBreaker().delay(), + introspector.getCircuitBreaker().delayUnit()); + if (breakerHelper.getCurrentStateNanos() > delayNanos) { + breakerHelper.setState(State.HALF_OPEN_MP); + } + } + logCircuitBreakerState("Enter"); + } - // Track invocation in a bulkhead - if (introspector.hasBulkhead()) { - bulkheadHelper.trackInvocation(this); - } + // Record state of breaker + boolean wasBreakerOpen = isCircuitBreakerOpen(); - // Execute command - Object result = null; - Throwable throwable = null; - long startNanos = System.nanoTime(); - try { - result = super.execute(); - } catch (Throwable t) { - throwable = t; - } + // Track invocation in a bulkhead + if (introspector.hasBulkhead()) { + bulkheadHelper.trackInvocation(this); + } - executionTime = System.nanoTime() - startNanos; - boolean hasFailed = (throwable != null); + // Execute command + Object result = null; + Throwable throwable = null; + long startNanos = System.nanoTime(); + try { + result = super.execute(); + } catch (Throwable t) { + throwable = t; + } - if (introspector.hasCircuitBreaker()) { - // Keep track of failure ratios - breakerHelper.pushResult(throwable == null); - - // Query breaker states - boolean breakerWillOpen = false; - boolean isClosedNow = !isCircuitBreakerOpen(); - - /* - * Special logic for MP circuit breakers to support failOn. If not a - * throwable to fail on, restore underlying breaker and return. - */ - if (hasFailed) { - final Throwable throwableFinal = throwable; - Class[] throwableClasses = introspector.getCircuitBreaker().failOn(); - boolean failOn = Arrays.asList(throwableClasses) - .stream() - .anyMatch(c -> c.isAssignableFrom(throwableFinal.getClass())); - if (!failOn) { - restoreBreaker(); // clears Hystrix counters - updateMetricsAfter(throwable, wasBreakerOpen, isClosedNow, breakerWillOpen); - throw ExceptionUtil.toWrappedException(throwable); + executionTime = System.nanoTime() - startNanos; + boolean hasFailed = (throwable != null); + + if (introspector.hasCircuitBreaker()) { + // Keep track of failure ratios + breakerHelper.pushResult(throwable == null); + + // Query breaker states + boolean breakerOpening = false; + boolean isClosedNow = !wasBreakerOpen; + + /* + * Special logic for MP circuit breakers to support failOn. If not a + * throwable to fail on, restore underlying breaker and return. + */ + if (hasFailed) { + final Throwable throwableFinal = throwable; + Class[] throwableClasses = introspector.getCircuitBreaker().failOn(); + boolean failOn = Arrays.asList(throwableClasses) + .stream() + .anyMatch(c -> c.isAssignableFrom(throwableFinal.getClass())); + if (!failOn) { + updateMetricsAfter(throwable, wasBreakerOpen, isClosedNow, breakerOpening); + logCircuitBreakerState("Exit 1"); + throw ExceptionUtil.toWrappedException(throwable); + } } - } - /* - * Special logic for MP circuit breakers to support an arbitrary success - * threshold used to return a breaker back to its CLOSED state. Hystrix - * only supports a threshold of 1 here, so additional logic is required. - */ - synchronized (breakerHelper.getSyncObject()) { - // If failure ratio exceeded, then switch state to OPEN_MP - if (breakerHelper.getState() == CircuitBreakerHelper.State.CLOSED_MP) { + // CLOSED_MP -> OPEN_MP + if (breakerHelper.getState() == State.CLOSED_MP) { double failureRatio = breakerHelper.getFailureRatio(); if (failureRatio >= introspector.getCircuitBreaker().failureRatio()) { - breakerWillOpen = true; - breakerHelper.setState(CircuitBreakerHelper.State.OPEN_MP); - runTripBreaker(); + breakerHelper.setState(State.OPEN_MP); + breakerOpening = true; } } - // If latest run failed, may need to switch state to OPEN_MP + // HALF_OPEN_MP -> OPEN_MP if (hasFailed) { - if (breakerHelper.getState() == CircuitBreakerHelper.State.HALF_OPEN_MP) { - // If failed and in HALF_OPEN_MP, we need to force breaker to open - runTripBreaker(); - breakerHelper.setState(CircuitBreakerHelper.State.OPEN_MP); + if (breakerHelper.getState() == State.HALF_OPEN_MP) { + breakerHelper.setState(State.OPEN_MP); } - updateMetricsAfter(throwable, wasBreakerOpen, isClosedNow, breakerWillOpen); + updateMetricsAfter(throwable, wasBreakerOpen, isClosedNow, breakerOpening); + logCircuitBreakerState("Exit 2"); throw ExceptionUtil.toWrappedException(throwable); } - // Check next state of breaker based on outcome - if (wasBreakerOpen && isClosedNow) { - // Last called was successful - breakerHelper.incSuccessCount(); + // Otherwise, increment success count + breakerHelper.incSuccessCount(); - // We stay in HALF_OPEN_MP until successThreshold is reached - if (breakerHelper.getSuccessCount() < introspector.getCircuitBreaker().successThreshold()) { - breakerHelper.setState(CircuitBreakerHelper.State.HALF_OPEN_MP); - } else { - breakerHelper.setState(CircuitBreakerHelper.State.CLOSED_MP); + // HALF_OPEN_MP -> CLOSED_MP + if (breakerHelper.getState() == State.HALF_OPEN_MP) { + if (breakerHelper.getSuccessCount() == introspector.getCircuitBreaker().successThreshold()) { + breakerHelper.setState(State.CLOSED_MP); breakerHelper.resetCommandData(); + lockRemoved = true; + isClosedNow = true; } } - } - updateMetricsAfter(throwable, wasBreakerOpen, isClosedNow, breakerWillOpen); - } + updateMetricsAfter(throwable, wasBreakerOpen, isClosedNow, breakerOpening); + } - // Untrack invocation in a bulkhead - if (introspector.hasBulkhead()) { - bulkheadHelper.untrackInvocation(this); - } + // Untrack invocation in a bulkhead + if (introspector.hasBulkhead()) { + bulkheadHelper.untrackInvocation(this); + } - // Display circuit breaker state at exit - if (introspector.hasCircuitBreaker()) { - LOGGER.info("Exit: breaker for " + getCommandKey() + " in state " + breakerHelper.getState()); - } + // Display circuit breaker state at exit + logCircuitBreakerState("Exit 3"); - // Outcome of execution - if (throwable != null) { - throw ExceptionUtil.toWrappedException(throwable); - } else { - return result; + // Outcome of execution + if (throwable != null) { + throw ExceptionUtil.toWrappedException(throwable); + } else { + return result; + } + } finally { + // Free lock unless command data was reset + if (introspector.hasCircuitBreaker() && !lockRemoved) { + breakerHelper.unlock(); + } } } @@ -400,53 +383,6 @@ private void updateMetricsAfter(Throwable throwable, boolean wasBreakerOpen, boo } } - /** - * Run a failing command for an entire window plus one to force a circuit breaker - * to open. Unfortunately, there is no access to the underlying circuit breaker - * so this is the only way to control its internal state. Notice the use of - * the same {@code commandKey}. - */ - private void runTripBreaker() { - if (!isCircuitBreakerOpen()) { - LOGGER.info("Attempting to trip circuit breaker for command " + commandKey); - final int windowSize = introspector.getCircuitBreaker().requestVolumeThreshold(); - for (int i = 0; i <= windowSize; i++) { - try { - new RunnableCommand(commandKey, () -> { - throw new RuntimeException("Oops"); - }).execute(); - } catch (Throwable t) { - // ignore - } - } - if (!isCircuitBreakerOpen()) { - LOGGER.info("Attempt to manually open breaker failed for command " - + commandKey); - } - } - } - - /** - * Run a successful command for an entire window plus one to force a circuit breaker - * to close. Unfortunately, there is no access to the underlying circuit breaker - * so this is the only way to control its internal state. Notice the use of - * the same {@code commandKey}. - */ - private void restoreBreaker() { - if (isCircuitBreakerOpen()) { - LOGGER.info("Attempting to restore circuit breaker for command " + commandKey); - final int windowSize = introspector.getCircuitBreaker().requestVolumeThreshold(); - for (int i = 0; i <= windowSize; i++) { - new RunnableCommand(commandKey, () -> { - }).execute(); - } - if (isCircuitBreakerOpen()) { - LOGGER.info("Attempt to manually close breaker failed for command " - + commandKey); - } - } - } - /** * Sets a Hystrix property on a command. * @@ -457,4 +393,18 @@ private void setProperty(String key, Object value) { final AbstractConfiguration configManager = ConfigurationManager.getConfigInstance(); configManager.setProperty(String.format("hystrix.command.%s.%s", commandKey, key), value); } + + /** + * Logs circuit breaker state, if one is present. + * + * @param preamble Message preamble. + */ + private void logCircuitBreakerState(String preamble) { + if (introspector.hasCircuitBreaker()) { + String hystrixState = isCircuitBreakerOpen() ? "OPEN" : "CLOSED"; + LOGGER.info(preamble + ": breaker for " + getCommandKey() + " in state " + + breakerHelper.getState() + " (Hystrix: " + hystrixState + + " Thread:" + Thread.currentThread().getName() + ")"); + } + } } diff --git a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/MethodIntrospector.java b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/MethodIntrospector.java index 17796d597f0..a9c3f345771 100644 --- a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/MethodIntrospector.java +++ b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/MethodIntrospector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,13 +182,10 @@ Map getHystrixProperties() { // Circuit breakers result.put("circuitBreaker.enabled", hasCircuitBreaker()); if (hasCircuitBreaker()) { - final CircuitBreaker circuitBreaker = getCircuitBreaker(); - result.put("circuitBreaker.requestVolumeThreshold", - circuitBreaker.requestVolumeThreshold()); - result.put("circuitBreaker.errorThresholdPercentage", - (int) (circuitBreaker.failureRatio() * 100)); - result.put("circuitBreaker.sleepWindowInMilliseconds", - TimeUtil.convertToMillis(circuitBreaker.delay(), circuitBreaker.delayUnit())); + // We are implementing this logic internally, so set to high values + result.put("circuitBreaker.requestVolumeThreshold", Integer.MAX_VALUE); + result.put("circuitBreaker.errorThresholdPercentage", 100); + result.put("circuitBreaker.sleepWindowInMilliseconds", Long.MAX_VALUE); } // Timeouts diff --git a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/MetricsTest.java b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/MetricsTest.java index f782b8e9646..ac8af0b5e92 100644 --- a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/MetricsTest.java +++ b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/MetricsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -214,7 +214,6 @@ public void testBreakerTrip() throws Exception { for (int i = 0; i < CircuitBreakerBean.REQUEST_VOLUME_THRESHOLD; i++) { assertThrows(RuntimeException.class, () -> bean.exerciseBreaker(false)); } - Thread.sleep(1000); assertThrows(CircuitBreakerOpenException.class, () -> bean.exerciseBreaker(false)); assertThat(getCounter(bean, "exerciseBreaker", @@ -249,7 +248,6 @@ public void testBreakerGauges() throws Exception { } assertThrows(RuntimeException.class, () -> bean.exerciseGauges(false)); - Thread.sleep(1000); assertThrows(CircuitBreakerOpenException.class, () -> bean.exerciseGauges(false)); assertThat(getGauge(bean, "exerciseGauges", diff --git a/pom.xml b/pom.xml index 1f43d229f17..a2cd35f18f4 100644 --- a/pom.xml +++ b/pom.xml @@ -154,7 +154,7 @@ 1.3.3 3.0.3.Final 2.6.0 - 1.5.12 + 1.5.18 1.1.0