use of org.eclipse.microprofile.faulttolerance.Bulkhead in project Payara by payara.
the class BulkheadInterceptor method bulkhead.
/**
* Proceeds the context under Bulkhead semantics.
* @param invocationContext The context to proceed.
* @return The outcome of the invocationContext
* @throws Exception
*/
private Object bulkhead(InvocationContext invocationContext) throws Exception {
Object proceededInvocationContext = null;
FaultToleranceService faultToleranceService = Globals.getDefaultBaseServiceLocator().getService(FaultToleranceService.class);
Bulkhead bulkhead = FaultToleranceCdiUtils.getAnnotation(beanManager, Bulkhead.class, invocationContext);
Config config = null;
try {
config = ConfigProvider.getConfig();
} catch (IllegalArgumentException ex) {
logger.log(Level.INFO, "No config could be found", ex);
}
int value = (Integer) FaultToleranceCdiUtils.getOverrideValue(config, Bulkhead.class, "value", invocationContext, Integer.class).orElse(bulkhead.value());
int waitingTaskQueue = (Integer) FaultToleranceCdiUtils.getOverrideValue(config, Bulkhead.class, "waitingTaskQueue", invocationContext, Integer.class).orElse(bulkhead.waitingTaskQueue());
InvocationManager invocationManager = Globals.getDefaultBaseServiceLocator().getService(InvocationManager.class);
String appName = faultToleranceService.getApplicationName(invocationManager, invocationContext);
Semaphore bulkheadExecutionSemaphore = faultToleranceService.getBulkheadExecutionSemaphore(appName, invocationContext.getMethod(), value);
// If the Asynchronous annotation is present, use threadpool style, otherwise use semaphore style
if (FaultToleranceCdiUtils.getAnnotation(beanManager, Asynchronous.class, invocationContext) != null) {
Semaphore bulkheadExecutionQueueSemaphore = faultToleranceService.getBulkheadExecutionQueueSemaphore(appName, invocationContext.getMethod(), waitingTaskQueue);
// Check if there are any free permits for concurrent execution
if (!bulkheadExecutionSemaphore.tryAcquire(0, TimeUnit.SECONDS)) {
logger.log(Level.FINER, "Attempting to acquire bulkhead queue semaphore.");
// If there aren't any free permits, see if there are any free queue permits
if (bulkheadExecutionQueueSemaphore.tryAcquire(0, TimeUnit.SECONDS)) {
logger.log(Level.FINER, "Acquired bulkhead queue semaphore.");
// If there is a free queue permit, queue for an executor permit
try {
logger.log(Level.FINER, "Attempting to acquire bulkhead execution semaphore.");
faultToleranceService.startFaultToleranceSpan(new RequestTraceSpan("obtainBulkheadSemaphore"), invocationManager, invocationContext);
try {
bulkheadExecutionSemaphore.acquire();
} finally {
// Make sure we end the trace right here
faultToleranceService.endFaultToleranceSpan();
}
logger.log(Level.FINER, "Acquired bulkhead queue semaphore.");
// Release the queue permit
bulkheadExecutionQueueSemaphore.release();
// Proceed the invocation and wait for the response
try {
logger.log(Level.FINER, "Proceeding bulkhead context");
proceededInvocationContext = invocationContext.proceed();
} catch (Exception ex) {
logger.log(Level.FINE, "Exception proceeding Bulkhead context", ex);
// Generic catch, as we need to release the semaphore permits
bulkheadExecutionSemaphore.release();
bulkheadExecutionQueueSemaphore.release();
// Let the exception propagate further up - we just want to release the semaphores
throw ex;
}
// Release the execution permit
bulkheadExecutionSemaphore.release();
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Interrupted acquiring bulkhead semaphore", ex);
throw new BulkheadException(ex);
}
} else {
throw new BulkheadException("No free work or queue permits.");
}
} else {
// Proceed the invocation and wait for the response
try {
logger.log(Level.FINER, "Proceeding bulkhead context");
proceededInvocationContext = invocationContext.proceed();
} catch (Exception ex) {
logger.log(Level.FINE, "Exception proceeding Bulkhead context", ex);
// Generic catch, as we need to release the semaphore permits
bulkheadExecutionSemaphore.release();
// Let the exception propagate further up - we just want to release the semaphores
throw ex;
}
// Release the permit
bulkheadExecutionSemaphore.release();
}
} else {
// Try to get an execution permit
if (bulkheadExecutionSemaphore.tryAcquire(0, TimeUnit.SECONDS)) {
// Proceed the invocation and wait for the response
try {
logger.log(Level.FINER, "Proceeding bulkhead context");
proceededInvocationContext = invocationContext.proceed();
} catch (Exception ex) {
logger.log(Level.FINE, "Exception proceeding Bulkhead context", ex);
// Generic catch, as we need to release the semaphore permits
bulkheadExecutionSemaphore.release();
// Let the exception propagate further up - we just want to release the semaphores
throw ex;
}
// Release the permit
bulkheadExecutionSemaphore.release();
} else {
throw new BulkheadException("No free work permits.");
}
}
return proceededInvocationContext;
}
use of org.eclipse.microprofile.faulttolerance.Bulkhead in project Payara by payara.
the class FaultToleranceStressTest method occasionallyFailingService_Method.
/**
* The method under tests fails every 3rd call whereby in a window of 4 there can be 2 failed calls opening the
* circuit. As delay is just recorded but not enforced there is only a minimal chance another caller does an attempt
* while the circuit is open but occasionally this happens.
*
* Every 5th call returns a failed Future that should be handed to the caller as is.
*
* Every 3rd call fails causing a retry. Together with open circuits this might even cause fallback handler to be
* used which will also fail the result as it only rethrows the error.
*/
@Asynchronous
@Fallback(FaultToleranceStressTest.class)
@Retry(maxRetries = 1)
@Bulkhead(value = 2, waitingTaskQueue = 2)
@CircuitBreaker(successThreshold = 2, delay = 0, requestVolumeThreshold = 4)
public Future<String> occasionallyFailingService_Method() throws IOException {
int called = methodInvocationCount.incrementAndGet();
if (called % 3 == 0) {
// this causes a retry
methodFailedInvocationCount.incrementAndGet();
throw new IOException("Failed");
}
if (called % 5 == 0) {
// this does not cause a retry, its simply a Future that completes with a failure
CompletableFuture<String> failedValue = new CompletableFuture<>();
failedValue.completeExceptionally(new IOException("Failed"));
return failedValue;
}
methodSuccessfulInvocationCount.incrementAndGet();
return CompletableFuture.completedFuture("Success");
}
Aggregations