use of org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException in project Payara by payara.
the class FaultTolerancePolicy method processCircuitBreakerStage.
/**
* Stage that takes care of the {@link CircuitBreakerPolicy} handling.
*/
private Object processCircuitBreakerStage(FaultToleranceInvocation invocation, AsyncFuture asyncAttempt) throws Exception {
if (!isCircuitBreakerPresent()) {
return processTimeoutStage(invocation, asyncAttempt);
}
logger.log(Level.FINER, "Proceeding invocation with circuitbreaker semantics");
CircuitBreakerState state = invocation.context.getState();
Object resultValue = null;
switch(state.getCircuitState()) {
default:
case OPEN:
logger.log(Level.FINER, "CircuitBreaker is open, throwing exception");
invocation.metrics.incrementCircuitbreakerCallsPreventedTotal();
throw new CircuitBreakerOpenException();
case HALF_OPEN:
logger.log(Level.FINER, "Proceeding half open CircuitBreaker context");
try {
resultValue = processTimeoutStage(invocation, asyncAttempt);
} catch (Exception | Error ex) {
if (circuitBreaker.isFailure(ex)) {
invocation.metrics.incrementCircuitbreakerCallsFailedTotal();
logger.log(Level.FINE, "Exception causes CircuitBreaker to transit: half-open => open");
openCircuit(invocation, state);
} else {
invocation.metrics.incrementCircuitbreakerCallsSucceededTotal();
}
throw ex;
}
if (state.halfOpenSuccessfulClosedCircuit(circuitBreaker.successThreshold)) {
logger.log(Level.FINE, "Success threshold causes CircuitBreaker to transit: half-open => closed");
}
invocation.metrics.incrementCircuitbreakerCallsSucceededTotal();
return resultValue;
case CLOSED:
logger.log(Level.FINER, "Proceeding closed CircuitBreaker context");
Throwable failedOn = null;
try {
resultValue = processTimeoutStage(invocation, asyncAttempt);
state.recordClosedOutcome(true);
} catch (Exception | Error ex) {
if (circuitBreaker.isFailure(ex)) {
state.recordClosedOutcome(false);
invocation.metrics.incrementCircuitbreakerCallsFailedTotal();
} else {
state.recordClosedOutcome(true);
invocation.metrics.incrementCircuitbreakerCallsSucceededTotal();
}
failedOn = ex;
}
if (state.isOverFailureThreshold()) {
logger.log(Level.FINE, "Failure threshold causes CircuitBreaker to transit: closed => open");
openCircuit(invocation, state);
}
if (failedOn != null) {
rethrow(failedOn);
}
invocation.metrics.incrementCircuitbreakerCallsSucceededTotal();
return resultValue;
}
}
use of org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException in project Payara by payara.
the class CircuitBreakerInterceptor method circuitBreak.
private Object circuitBreak(InvocationContext invocationContext) throws Exception {
Object proceededInvocationContext = null;
FaultToleranceService faultToleranceService = Globals.getDefaultBaseServiceLocator().getService(FaultToleranceService.class);
CircuitBreaker circuitBreaker = FaultToleranceCdiUtils.getAnnotation(beanManager, CircuitBreaker.class, invocationContext);
Config config = null;
try {
config = ConfigProvider.getConfig();
} catch (IllegalArgumentException ex) {
logger.log(Level.INFO, "No config could be found", ex);
}
Class<? extends Throwable>[] failOn = circuitBreaker.failOn();
try {
String failOnString = ((String) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "failOn", invocationContext, String.class).get());
List<Class> classList = new ArrayList<>();
// Remove any curly or square brackets from the string, as well as any spaces and ".class"es and loop
for (String className : failOnString.replaceAll("[\\{\\[ \\]\\}]", "").replaceAll("\\.class", "").split(",")) {
// Get a class object
classList.add(Class.forName(className));
}
failOn = classList.toArray(failOn);
} catch (NoSuchElementException nsee) {
logger.log(Level.FINER, "Could not find element in config", nsee);
} catch (ClassNotFoundException cnfe) {
logger.log(Level.INFO, "Could not find class from failOn config, defaulting to annotation. " + "Make sure you give the full canonical class name.", cnfe);
}
long delay = (Long) FaultToleranceCdiUtils.getOverrideValue(config, CircuitBreaker.class, "value", invocationContext, Long.class).orElse(circuitBreaker.delay());
ChronoUnit delayUnit = (ChronoUnit) FaultToleranceCdiUtils.getOverrideValue(config, CircuitBreaker.class, "delayUnit", invocationContext, ChronoUnit.class).orElse(circuitBreaker.delayUnit());
int requestVolumeThreshold = (Integer) FaultToleranceCdiUtils.getOverrideValue(config, CircuitBreaker.class, "requestVolumeThreshold", invocationContext, Integer.class).orElse(circuitBreaker.requestVolumeThreshold());
double failureRatio = (Double) FaultToleranceCdiUtils.getOverrideValue(config, CircuitBreaker.class, "failureRatio", invocationContext, Double.class).orElse(circuitBreaker.failureRatio());
int successThreshold = (Integer) FaultToleranceCdiUtils.getOverrideValue(config, CircuitBreaker.class, "successThreshold", invocationContext, Integer.class).orElse(circuitBreaker.successThreshold());
long delayMillis = Duration.of(delay, delayUnit).toMillis();
InvocationManager invocationManager = Globals.getDefaultBaseServiceLocator().getService(InvocationManager.class);
CircuitBreakerState circuitBreakerState = faultToleranceService.getCircuitBreakerState(faultToleranceService.getApplicationName(invocationManager, invocationContext), invocationContext.getMethod(), circuitBreaker);
switch(circuitBreakerState.getCircuitState()) {
case OPEN:
logger.log(Level.FINER, "CircuitBreaker is Open, throwing exception");
// If open, immediately throw an error
throw new CircuitBreakerOpenException("CircuitBreaker for method " + invocationContext.getMethod().getName() + "is in state OPEN.");
case CLOSED:
// If closed, attempt to proceed the invocation context
try {
logger.log(Level.FINER, "Proceeding CircuitBreaker context");
proceededInvocationContext = invocationContext.proceed();
} catch (Exception ex) {
logger.log(Level.FINE, "Exception executing CircuitBreaker context");
// Check if the exception is something that should record a failure
if (shouldFail(failOn, ex)) {
logger.log(Level.FINE, "Caught exception is included in CircuitBreaker failOn, " + "recording failure against CircuitBreaker");
// Add a failure result to the queue
circuitBreakerState.recordClosedResult(Boolean.FALSE);
// Calculate the failure threshold
long failureThreshold = Math.round(requestVolumeThreshold * failureRatio);
// If we're over the failure threshold, open the circuit
if (circuitBreakerState.isOverFailureThreshold(failureThreshold)) {
logger.log(Level.FINE, "CircuitBreaker is over failure threshold {0}, opening circuit", failureThreshold);
circuitBreakerState.setCircuitState(CircuitBreakerState.CircuitState.OPEN);
// Kick off a thread that will half-open the circuit after the specified delay
scheduleHalfOpen(delayMillis, circuitBreakerState);
}
}
// Finally, propagate the error upwards
throw ex;
}
// If everything is bon, just add a success value
circuitBreakerState.recordClosedResult(Boolean.TRUE);
break;
case HALF_OPEN:
// If half-open, attempt to proceed the invocation context
try {
logger.log(Level.FINER, "Proceeding half open CircuitBreaker context");
proceededInvocationContext = invocationContext.proceed();
} catch (Exception ex) {
logger.log(Level.FINE, "Exception executing CircuitBreaker context");
// Check if the exception is something that should record a failure
if (shouldFail(failOn, ex)) {
logger.log(Level.FINE, "Caught exception is included in CircuitBreaker failOn, " + "reopening half open circuit");
// Open the circuit again, and reset the half-open result counter
circuitBreakerState.setCircuitState(CircuitBreakerState.CircuitState.OPEN);
circuitBreakerState.resetHalfOpenSuccessfulResultCounter();
scheduleHalfOpen(delayMillis, circuitBreakerState);
}
throw ex;
}
// If the invocation context hasn't thrown an error, record a success
circuitBreakerState.incrementHalfOpenSuccessfulResultCounter();
logger.log(Level.FINER, "Number of consecutive successful circuitbreaker executions = {0}", circuitBreakerState.getHalfOpenSuccessFulResultCounter());
// If we've hit the success threshold, close the circuit
if (circuitBreakerState.getHalfOpenSuccessFulResultCounter() == successThreshold) {
logger.log(Level.FINE, "Number of consecutive successful CircuitBreaker executions is above " + "threshold {0}, closing circuit", successThreshold);
circuitBreakerState.setCircuitState(CircuitBreakerState.CircuitState.CLOSED);
// Reset the counter for when we next need to use it
circuitBreakerState.resetHalfOpenSuccessfulResultCounter();
// Reset the rolling results window
circuitBreakerState.resetResults();
}
break;
}
return proceededInvocationContext;
}
use of org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException in project wildfly-swarm by wildfly-swarm.
the class HystrixCommandInterceptor method interceptCommand.
@AroundInvoke
public Object interceptCommand(InvocationContext ic) throws Exception {
Method method = ic.getMethod();
ExecutionContextWithInvocationContext ctx = new ExecutionContextWithInvocationContext(ic);
boolean shouldRunCommand = true;
Object res = null;
LOGGER.tracef("FT operation intercepted: %s", method);
CommandMetadata metadata = commandMetadataMap.computeIfAbsent(method, CommandMetadata::new);
RetryContext retryContext = nonFallBackEnable && metadata.operation.hasRetry() ? new RetryContext(metadata.operation.getRetry()) : null;
SynchronousCircuitBreaker syncCircuitBreaker = null;
while (shouldRunCommand) {
shouldRunCommand = false;
if (nonFallBackEnable && syncCircuitBreakerEnabled && metadata.hasCircuitBreaker()) {
syncCircuitBreaker = getSynchronousCircuitBreaker(metadata.commandKey, metadata.operation.getCircuitBreaker());
}
Supplier<Object> fallback = null;
if (retryContext == null || retryContext.isLastAttempt()) {
fallback = metadata.getFallback(ctx);
}
DefaultCommand command = new DefaultCommand(metadata.setter, ctx, fallback);
try {
if (metadata.operation.isAsync()) {
LOGGER.debugf("Queue up command for async execution: %s", metadata.operation);
res = new AsyncFuture(command.queue());
} else {
LOGGER.debugf("Sync execution: %s]", metadata.operation);
res = command.execute();
}
if (syncCircuitBreaker != null) {
syncCircuitBreaker.executionSucceeded();
}
} catch (HystrixRuntimeException e) {
if (syncCircuitBreaker != null) {
syncCircuitBreaker.executionFailed();
}
HystrixRuntimeException.FailureType failureType = e.getFailureType();
LOGGER.tracef("Hystrix runtime failure [%s] when invoking %s", failureType, method);
switch(failureType) {
case TIMEOUT:
TimeoutException timeoutException = new TimeoutException(e);
if (retryContext != null && retryContext.shouldRetry()) {
shouldRunCommand = shouldRetry(retryContext, timeoutException);
if (shouldRunCommand) {
continue;
}
}
throw timeoutException;
case SHORTCIRCUIT:
throw new CircuitBreakerOpenException(method.getName());
case REJECTED_THREAD_EXECUTION:
case REJECTED_SEMAPHORE_EXECUTION:
case REJECTED_SEMAPHORE_FALLBACK:
BulkheadException bulkheadException = new BulkheadException(e);
if (retryContext != null && retryContext.shouldRetry()) {
shouldRunCommand = shouldRetry(retryContext, bulkheadException);
if (shouldRunCommand) {
continue;
}
}
throw bulkheadException;
case COMMAND_EXCEPTION:
if (retryContext != null && retryContext.shouldRetry()) {
shouldRunCommand = shouldRetry(retryContext, getCause(e));
continue;
}
default:
throw getCause(e);
}
}
}
return res;
}
Aggregations