Search in sources :

Example 1 with Bulkhead

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;
}
Also used : Asynchronous(org.eclipse.microprofile.faulttolerance.Asynchronous) Config(org.eclipse.microprofile.config.Config) InvocationManager(org.glassfish.api.invocation.InvocationManager) RequestTraceSpan(fish.payara.notification.requesttracing.RequestTraceSpan) Semaphore(java.util.concurrent.Semaphore) FaultToleranceService(fish.payara.microprofile.faulttolerance.FaultToleranceService) BulkheadException(org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException) Bulkhead(org.eclipse.microprofile.faulttolerance.Bulkhead) BulkheadException(org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException)

Example 2 with Bulkhead

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");
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) Asynchronous(org.eclipse.microprofile.faulttolerance.Asynchronous) CircuitBreaker(org.eclipse.microprofile.faulttolerance.CircuitBreaker) Bulkhead(org.eclipse.microprofile.faulttolerance.Bulkhead) Fallback(org.eclipse.microprofile.faulttolerance.Fallback) Retry(org.eclipse.microprofile.faulttolerance.Retry)

Aggregations

Asynchronous (org.eclipse.microprofile.faulttolerance.Asynchronous)2 Bulkhead (org.eclipse.microprofile.faulttolerance.Bulkhead)2 FaultToleranceService (fish.payara.microprofile.faulttolerance.FaultToleranceService)1 RequestTraceSpan (fish.payara.notification.requesttracing.RequestTraceSpan)1 IOException (java.io.IOException)1 UncheckedIOException (java.io.UncheckedIOException)1 CompletableFuture (java.util.concurrent.CompletableFuture)1 Semaphore (java.util.concurrent.Semaphore)1 Config (org.eclipse.microprofile.config.Config)1 CircuitBreaker (org.eclipse.microprofile.faulttolerance.CircuitBreaker)1 Fallback (org.eclipse.microprofile.faulttolerance.Fallback)1 Retry (org.eclipse.microprofile.faulttolerance.Retry)1 BulkheadException (org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException)1 InvocationManager (org.glassfish.api.invocation.InvocationManager)1