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;
}
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;
}
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));
}
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();
}
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;
}
Aggregations