Search in sources :

Example 1 with BulkheadException

use of org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException 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)

Aggregations

FaultToleranceService (fish.payara.microprofile.faulttolerance.FaultToleranceService)1 RequestTraceSpan (fish.payara.notification.requesttracing.RequestTraceSpan)1 Semaphore (java.util.concurrent.Semaphore)1 Config (org.eclipse.microprofile.config.Config)1 Asynchronous (org.eclipse.microprofile.faulttolerance.Asynchronous)1 Bulkhead (org.eclipse.microprofile.faulttolerance.Bulkhead)1 BulkheadException (org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException)1 InvocationManager (org.glassfish.api.invocation.InvocationManager)1