Search in sources :

Example 1 with Retry

use of org.eclipse.microprofile.faulttolerance.Retry in project Payara by payara.

the class CircuitBreakerInterceptor method intercept.

@AroundInvoke
public Object intercept(InvocationContext invocationContext) throws Exception {
    Object proceededInvocationContext = null;
    FaultToleranceService faultToleranceService = Globals.getDefaultBaseServiceLocator().getService(FaultToleranceService.class);
    InvocationManager invocationManager = Globals.getDefaultBaseServiceLocator().getService(InvocationManager.class);
    Config config = null;
    try {
        config = ConfigProvider.getConfig();
    } catch (IllegalArgumentException ex) {
        logger.log(Level.INFO, "No config could be found", ex);
    }
    // Attempt to proceed the invocation with CircuitBreaker semantics if Fault Tolerance is enabled
    try {
        if (faultToleranceService.isFaultToleranceEnabled(faultToleranceService.getApplicationName(invocationManager, invocationContext), config)) {
            logger.log(Level.FINER, "Proceeding invocation with circuitbreaker semantics");
            proceededInvocationContext = circuitBreak(invocationContext);
        } else {
            // If fault tolerance isn't enabled, just proceed as normal
            logger.log(Level.FINE, "Fault Tolerance not enabled for {0}, proceeding normally without " + "circuitbreaker.", faultToleranceService.getApplicationName(invocationManager, invocationContext));
            proceededInvocationContext = invocationContext.proceed();
        }
    } catch (Exception ex) {
        Retry retry = FaultToleranceCdiUtils.getAnnotation(beanManager, Retry.class, invocationContext);
        if (retry != null) {
            logger.log(Level.FINE, "Retry annotation found on method, propagating error upwards.");
            throw ex;
        } else {
            Fallback fallback = FaultToleranceCdiUtils.getAnnotation(beanManager, Fallback.class, invocationContext);
            if (fallback != null) {
                logger.log(Level.FINE, "Fallback annotation found on method, and no Retry annotation - " + "falling back from CircuitBreaker");
                FallbackPolicy fallbackPolicy = new FallbackPolicy(fallback, config, invocationContext);
                proceededInvocationContext = fallbackPolicy.fallback(invocationContext);
            } else {
                throw ex;
            }
        }
    }
    return proceededInvocationContext;
}
Also used : FallbackPolicy(fish.payara.microprofile.faulttolerance.interceptors.fallback.FallbackPolicy) Config(org.eclipse.microprofile.config.Config) InvocationManager(org.glassfish.api.invocation.InvocationManager) Fallback(org.eclipse.microprofile.faulttolerance.Fallback) Retry(org.eclipse.microprofile.faulttolerance.Retry) FaultToleranceService(fish.payara.microprofile.faulttolerance.FaultToleranceService) NamingException(javax.naming.NamingException) NoSuchElementException(java.util.NoSuchElementException) CircuitBreakerOpenException(org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException) AroundInvoke(javax.interceptor.AroundInvoke)

Example 2 with Retry

use of org.eclipse.microprofile.faulttolerance.Retry in project Payara by payara.

the class RetryInterceptor method retry.

/**
 * Proceeds the given invocation context with Retry semantics.
 * @param invocationContext The invocation context to proceed
 * @return The proceeded invocation context
 * @throws Exception If the invocation throws an exception that shouldn't be retried, or if all retry attempts are
 * expended
 */
private Object retry(InvocationContext invocationContext) throws Exception {
    Object proceededInvocationContext = null;
    Retry retry = FaultToleranceCdiUtils.getAnnotation(beanManager, Retry.class, invocationContext);
    FaultToleranceService faultToleranceService = Globals.getDefaultBaseServiceLocator().getService(FaultToleranceService.class);
    InvocationManager invocationManager = Globals.getDefaultBaseServiceLocator().getService(InvocationManager.class);
    try {
        proceededInvocationContext = invocationContext.proceed();
    } catch (Exception ex) {
        Config config = null;
        try {
            config = ConfigProvider.getConfig();
        } catch (IllegalArgumentException iae) {
            logger.log(Level.INFO, "No config could be found", ex);
        }
        Class<? extends Throwable>[] retryOn = retry.retryOn();
        try {
            String retryOnString = ((String) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "retryOn", 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
            for (String className : retryOnString.replaceAll("[\\{\\[ \\]\\}]", "").replaceAll("\\.class", "").split(",")) {
                classList.add(Class.forName(className));
            }
            retryOn = classList.toArray(retryOn);
        } 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 retryOn config, defaulting to annotation. " + "Make sure you give the full canonical class name.", cnfe);
        }
        Class<? extends Throwable>[] abortOn = retry.abortOn();
        try {
            String abortOnString = (String) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "abortOn", 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
            for (String className : abortOnString.replaceAll("[\\{\\[ \\]\\}]", "").replaceAll("\\.class", "").split(",")) {
                classList.add(Class.forName(className));
            }
            abortOn = classList.toArray(abortOn);
        } 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 abortOn config, defaulting to annotation. " + "Make sure you give the full canonical class name.", cnfe);
        }
        if (!shouldRetry(retryOn, abortOn, ex)) {
            logger.log(Level.FINE, "Exception is contained in retryOn or abortOn, not retrying.", ex);
            throw ex;
        }
        int maxRetries = (Integer) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "maxRetries", invocationContext, Integer.class).orElse(retry.maxRetries());
        long delay = (Long) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "delay", invocationContext, Long.class).orElse(retry.delay());
        ChronoUnit delayUnit = (ChronoUnit) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "delayUnit", invocationContext, ChronoUnit.class).orElse(retry.delayUnit());
        long maxDuration = (Long) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "maxDuration", invocationContext, Long.class).orElse(retry.maxDuration());
        ChronoUnit durationUnit = (ChronoUnit) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "durationUnit", invocationContext, ChronoUnit.class).orElse(retry.durationUnit());
        long jitter = (Long) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "jitter", invocationContext, Long.class).orElse(retry.jitter());
        ChronoUnit jitterDelayUnit = (ChronoUnit) FaultToleranceCdiUtils.getOverrideValue(config, Retry.class, "jitterDelayUnit", invocationContext, ChronoUnit.class).orElse(retry.jitterDelayUnit());
        long delayMillis = Duration.of(delay, delayUnit).toMillis();
        long jitterMillis = Duration.of(jitter, jitterDelayUnit).toMillis();
        long timeoutTime = System.currentTimeMillis() + Duration.of(maxDuration, durationUnit).toMillis();
        Exception retryException = ex;
        faultToleranceService.startFaultToleranceSpan(new RequestTraceSpan("retryMethod"), invocationManager, invocationContext);
        try {
            if (maxRetries == -1 && maxDuration > 0) {
                logger.log(Level.FINER, "Retrying until maxDuration is breached.");
                while (System.currentTimeMillis() < timeoutTime) {
                    try {
                        proceededInvocationContext = invocationContext.proceed();
                        break;
                    } catch (Exception caughtException) {
                        retryException = caughtException;
                        if (!shouldRetry(retryOn, abortOn, caughtException)) {
                            break;
                        }
                        if (delayMillis > 0 || jitterMillis > 0) {
                            faultToleranceService.startFaultToleranceSpan(new RequestTraceSpan("delayRetry"), invocationManager, invocationContext);
                            try {
                                Thread.sleep(delayMillis + ThreadLocalRandom.current().nextLong(0, jitterMillis));
                            } finally {
                                faultToleranceService.endFaultToleranceSpan();
                            }
                        }
                    }
                }
            } else if (maxRetries == -1 && maxDuration == 0) {
                logger.log(Level.INFO, "Retrying potentially forever!");
                while (true) {
                    try {
                        proceededInvocationContext = invocationContext.proceed();
                        break;
                    } catch (Exception caughtException) {
                        retryException = caughtException;
                        if (!shouldRetry(retryOn, abortOn, caughtException)) {
                            break;
                        }
                        if (delayMillis > 0 || jitterMillis > 0) {
                            faultToleranceService.startFaultToleranceSpan(new RequestTraceSpan("delayRetry"), invocationManager, invocationContext);
                            try {
                                Thread.sleep(delayMillis + ThreadLocalRandom.current().nextLong(0, jitterMillis));
                            } finally {
                                faultToleranceService.endFaultToleranceSpan();
                            }
                        }
                    }
                }
            } else if (maxRetries != -1 && maxDuration > 0) {
                logger.log(Level.INFO, "Retrying as long as maxDuration ({0}ms) isn''t breached, and no more than {1} times", new Object[] { Duration.of(maxDuration, durationUnit).toMillis(), maxRetries });
                while (maxRetries > 0 && System.currentTimeMillis() < timeoutTime) {
                    try {
                        proceededInvocationContext = invocationContext.proceed();
                        break;
                    } catch (Exception caughtException) {
                        retryException = caughtException;
                        if (!shouldRetry(retryOn, abortOn, caughtException)) {
                            break;
                        }
                        if (delayMillis > 0 || jitterMillis > 0) {
                            faultToleranceService.startFaultToleranceSpan(new RequestTraceSpan("delayRetry"), invocationManager, invocationContext);
                            try {
                                Thread.sleep(delayMillis + ThreadLocalRandom.current().nextLong(0, jitterMillis));
                            } finally {
                                faultToleranceService.endFaultToleranceSpan();
                            }
                        }
                        maxRetries--;
                    }
                }
            } else {
                logger.log(Level.INFO, "Retrying no more than {0} times", maxRetries);
                while (maxRetries > 0) {
                    try {
                        proceededInvocationContext = invocationContext.proceed();
                        break;
                    } catch (Exception caughtException) {
                        retryException = caughtException;
                        if (!shouldRetry(retryOn, abortOn, caughtException)) {
                            break;
                        }
                        if (delayMillis > 0 || jitterMillis > 0) {
                            faultToleranceService.startFaultToleranceSpan(new RequestTraceSpan("delayRetry"), invocationManager, invocationContext);
                            try {
                                Thread.sleep(delayMillis + ThreadLocalRandom.current().nextLong(0, jitterMillis));
                            } finally {
                                faultToleranceService.endFaultToleranceSpan();
                            }
                        }
                        maxRetries--;
                    }
                }
            }
        } finally {
            faultToleranceService.endFaultToleranceSpan();
        }
        if (proceededInvocationContext == null) {
            throw retryException;
        }
    }
    return proceededInvocationContext;
}
Also used : Config(org.eclipse.microprofile.config.Config) InvocationManager(org.glassfish.api.invocation.InvocationManager) RequestTraceSpan(fish.payara.notification.requesttracing.RequestTraceSpan) FaultToleranceService(fish.payara.microprofile.faulttolerance.FaultToleranceService) NoSuchElementException(java.util.NoSuchElementException) ArrayList(java.util.ArrayList) List(java.util.List) Retry(org.eclipse.microprofile.faulttolerance.Retry) NoSuchElementException(java.util.NoSuchElementException) ChronoUnit(java.time.temporal.ChronoUnit)

Example 3 with Retry

use of org.eclipse.microprofile.faulttolerance.Retry in project Payara by payara.

the class ConfigOverridePriorityTest method onlyClassLevelAnnotationPresent.

@Test
public void onlyClassLevelAnnotationPresent() {
    Method annotatedMethod = TestUtils.getAnnotatedMethod();
    FaultToleranceConfig config = configFactory.bindTo(new StaticAnalysisContext(getClass(), annotatedMethod));
    Retry annotation = config.getAnnotation(Retry.class);
    assertEquals(ChronoUnit.MINUTES, config.delayUnit(annotation));
    overrides.override(Retry.class, "delayUnit", ChronoUnit.CENTURIES);
    assertEquals("should be: global override effective", ChronoUnit.CENTURIES, config.delayUnit(annotation));
    overrides.override(getClass(), Retry.class, "delayUnit", ChronoUnit.DAYS);
    assertEquals("should be: class level override effective because annotation present on class level", ChronoUnit.DAYS, config.delayUnit(annotation));
    overrides.override(annotatedMethod, Retry.class, "delayUnit", ChronoUnit.HOURS);
    assertEquals("should be: method level override ineffective because no method level annotation present", ChronoUnit.DAYS, config.delayUnit(annotation));
}
Also used : StaticAnalysisContext(fish.payara.microprofile.faulttolerance.policy.StaticAnalysisContext) FaultToleranceConfig(fish.payara.microprofile.faulttolerance.FaultToleranceConfig) Method(java.lang.reflect.Method) Retry(org.eclipse.microprofile.faulttolerance.Retry) Test(org.junit.Test)

Example 4 with Retry

use of org.eclipse.microprofile.faulttolerance.Retry in project quickstart by wildfly.

the class CoffeeResource method coffees.

/**
 * Provides list of all our coffees.
 * <p>
 * This method fails about 50% of time. However, in case of a failure, the method is automatically re-invoked again
 * (up to 4 times), thanks to the {@link Retry} annotation. That means that a user is rarely exposed to a
 * failure, since the probability of a failure occurring 4 times in row is fairly low.
 */
@GET
@Retry(maxRetries = 4, retryOn = RuntimeException.class)
public List<Coffee> coffees() {
    final Long invocationNumber = counter.getAndIncrement();
    maybeFail(String.format("CoffeeResource#coffees() invocation #%d failed", invocationNumber));
    LOGGER.infof("CoffeeResource#coffees() invocation #%d returning successfully", invocationNumber);
    return coffeeRepository.getAllCoffees();
}
Also used : AtomicLong(java.util.concurrent.atomic.AtomicLong) GET(javax.ws.rs.GET) Retry(org.eclipse.microprofile.faulttolerance.Retry)

Example 5 with Retry

use of org.eclipse.microprofile.faulttolerance.Retry in project Payara by payara.

the class BulkheadInterceptor method intercept.

@AroundInvoke
public Object intercept(InvocationContext invocationContext) throws Exception {
    Object proceededInvocationContext = null;
    FaultToleranceService faultToleranceService = Globals.getDefaultBaseServiceLocator().getService(FaultToleranceService.class);
    InvocationManager invocationManager = Globals.getDefaultBaseServiceLocator().getService(InvocationManager.class);
    Config config = null;
    try {
        config = ConfigProvider.getConfig();
    } catch (IllegalArgumentException ex) {
        logger.log(Level.INFO, "No config could be found", ex);
    }
    try {
        String appName = faultToleranceService.getApplicationName(invocationManager, invocationContext);
        // Attempt to proceed the InvocationContext with Bulkhead semantics if Fault Tolerance is enabled
        if (faultToleranceService.isFaultToleranceEnabled(appName, config)) {
            logger.log(Level.FINER, "Proceeding invocation with bulkhead semantics");
            proceededInvocationContext = bulkhead(invocationContext);
        } else {
            // If fault tolerance isn't enabled, just proceed as normal
            logger.log(Level.FINE, "Fault Tolerance not enabled for {0}, proceeding normally without bulkhead.", faultToleranceService.getApplicationName(invocationManager, invocationContext));
            proceededInvocationContext = invocationContext.proceed();
        }
    } catch (Exception ex) {
        Retry retry = FaultToleranceCdiUtils.getAnnotation(beanManager, Retry.class, invocationContext);
        if (retry != null) {
            logger.log(Level.FINE, "Retry annotation found on method, propagating error upwards.");
            throw ex;
        } else {
            // If an exception was thrown, check if the method is annotated with @Fallback
            Fallback fallback = FaultToleranceCdiUtils.getAnnotation(beanManager, Fallback.class, invocationContext);
            // If the method was annotated with Fallback, attempt it, otherwise just propagate the exception upwards
            if (fallback != null) {
                logger.log(Level.FINE, "Fallback annotation found on method, and no Retry annotation - " + "falling back from Bulkhead");
                FallbackPolicy fallbackPolicy = new FallbackPolicy(fallback, config, invocationContext);
                proceededInvocationContext = fallbackPolicy.fallback(invocationContext);
            } else {
                logger.log(Level.FINE, "Fallback annotation not found on method, propagating error upwards.", ex);
                throw ex;
            }
        }
    }
    return proceededInvocationContext;
}
Also used : FallbackPolicy(fish.payara.microprofile.faulttolerance.interceptors.fallback.FallbackPolicy) Config(org.eclipse.microprofile.config.Config) InvocationManager(org.glassfish.api.invocation.InvocationManager) Fallback(org.eclipse.microprofile.faulttolerance.Fallback) Retry(org.eclipse.microprofile.faulttolerance.Retry) FaultToleranceService(fish.payara.microprofile.faulttolerance.FaultToleranceService) BulkheadException(org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException) AroundInvoke(javax.interceptor.AroundInvoke)

Aggregations

Retry (org.eclipse.microprofile.faulttolerance.Retry)8 FaultToleranceService (fish.payara.microprofile.faulttolerance.FaultToleranceService)4 Config (org.eclipse.microprofile.config.Config)4 Fallback (org.eclipse.microprofile.faulttolerance.Fallback)4 InvocationManager (org.glassfish.api.invocation.InvocationManager)4 FallbackPolicy (fish.payara.microprofile.faulttolerance.interceptors.fallback.FallbackPolicy)3 AroundInvoke (javax.interceptor.AroundInvoke)3 FaultToleranceConfig (fish.payara.microprofile.faulttolerance.FaultToleranceConfig)2 StaticAnalysisContext (fish.payara.microprofile.faulttolerance.policy.StaticAnalysisContext)2 Method (java.lang.reflect.Method)2 NoSuchElementException (java.util.NoSuchElementException)2 NamingException (javax.naming.NamingException)2 Test (org.junit.Test)2 RequestTraceSpan (fish.payara.notification.requesttracing.RequestTraceSpan)1 IOException (java.io.IOException)1 UncheckedIOException (java.io.UncheckedIOException)1 ChronoUnit (java.time.temporal.ChronoUnit)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 CompletableFuture (java.util.concurrent.CompletableFuture)1