From e3c7965ca331d8761897c52b56d5b4aa2c0fa114 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Wed, 10 Apr 2024 17:30:04 +0200 Subject: [PATCH] Upgrade to SmallRye Fault Tolerance 6.3.0 --- bom/application/pom.xml | 2 +- .../asciidoc/smallrye-fault-tolerance.adoc | 4 +-- .../faulttolerance/deployment/DotNames.java | 4 ++- .../deployment/FaultToleranceScanner.java | 4 ++- .../SmallRyeFaultToleranceProcessor.java | 16 ++++++++-- .../dev-ui/qwc-fault-tolerance-methods.js | 10 ++++++ .../additional/AsyncNonBlockingService.java | 2 +- .../additional/BlockingService.java | 2 +- .../additional/NonblockingService.java | 2 +- .../NoncompatNonblockingService.java | 2 +- .../test/ratelimit/RateLimitTest.java | 4 ++- .../when/IsIllegalArgumentException.java | 10 ++++++ .../test/retry/when/IsNull.java | 10 ++++++ .../RetryOnAndRetryWhenExceptionService.java | 15 +++++++++ .../RetryOnAndRetryWhenExceptionTest.java | 27 ++++++++++++++++ .../RetryOnClassRetryWhenOnMethodService.java | 16 ++++++++++ .../RetryOnClassRetryWhenOnMethodTest.java | 27 ++++++++++++++++ .../RetryOnMethodRetryWhenOnClassService.java | 16 ++++++++++ .../RetryOnMethodRetryWhenOnClassTest.java | 27 ++++++++++++++++ .../RetryWhenResultAndExceptionService.java | 31 +++++++++++++++++++ .../when/RetryWhenResultAndExceptionTest.java | 26 ++++++++++++++++ .../SmallRyeFaultToleranceRecorder.java | 2 +- .../devui/FaultToleranceJsonRpcService.java | 6 ++++ 23 files changed, 252 insertions(+), 13 deletions(-) create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsIllegalArgumentException.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsNull.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionService.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionTest.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodService.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodTest.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassService.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassTest.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionService.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionTest.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index bf068f93dfd8f..246f6401f7dff 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -56,7 +56,7 @@ 4.0.0 3.10.0 2.8.2 - 6.2.6 + 6.3.0 4.5.0 2.1.0 1.0.13 diff --git a/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc b/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc index 568489a3f8f84..ea0c8b6dc7aa2 100644 --- a/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc +++ b/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc @@ -503,7 +503,7 @@ implementation("io.quarkus:quarkus-smallrye-fault-tolerance") == Additional resources SmallRye Fault Tolerance has more features than shown here. -Please check the link:https://smallrye.io/docs/smallrye-fault-tolerance/6.2.6/index.html[SmallRye Fault Tolerance documentation] to learn about them. +Please check the link:https://smallrye.io/docs/smallrye-fault-tolerance/6.3.0/index.html[SmallRye Fault Tolerance documentation] to learn about them. In Quarkus, you can use the SmallRye Fault Tolerance optional features out of the box. @@ -535,7 +535,7 @@ smallrye.faulttolerance.mp-compatibility=true ---- ==== -The link:https://smallrye.io/docs/smallrye-fault-tolerance/6.2.6/reference/programmatic-api.html[programmatic API] is present, including Mutiny support, and integrated with the declarative, annotation-based API. +The link:https://smallrye.io/docs/smallrye-fault-tolerance/6.3.0/reference/programmatic-api.html[programmatic API] is present, including Mutiny support, and integrated with the declarative, annotation-based API. You can use the `FaultTolerance` and `MutinyFaultTolerance` APIs out of the box. Support for Kotlin is present (assuming you use the Quarkus extension for Kotlin), so you can guard your `suspend` functions with fault tolerance annotations. diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/DotNames.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/DotNames.java index 9a95de94793a6..c18bc940a2535 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/DotNames.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/DotNames.java @@ -22,6 +22,7 @@ import io.smallrye.faulttolerance.api.ExponentialBackoff; import io.smallrye.faulttolerance.api.FibonacciBackoff; import io.smallrye.faulttolerance.api.RateLimit; +import io.smallrye.faulttolerance.api.RetryWhen; public final class DotNames { public static final DotName OBJECT = DotName.createSimple(Object.class); @@ -52,8 +53,9 @@ public final class DotNames { public static final DotName FIBONACCI_BACKOFF = DotName.createSimple(FibonacciBackoff.class); public static final DotName CUSTOM_BACKOFF = DotName.createSimple(CustomBackoff.class); public static final DotName CUSTOM_BACKOFF_STRATEGY = DotName.createSimple(CustomBackoffStrategy.class); + public static final DotName RETRY_WHEN = DotName.createSimple(RetryWhen.class); - // certain SmallRye annotations (@CircuitBreakerName, @[Non]Blocking, @*Backoff) alone do _not_ trigger + // certain SmallRye annotations (@CircuitBreakerName, @[Non]Blocking, @*Backoff, @RetryWhen) alone do _not_ trigger // the fault tolerance interceptor, only in combination with other fault tolerance annotations public static final Set FT_ANNOTATIONS = Set.of(APPLY_FAULT_TOLERANCE, ASYNCHRONOUS, ASYNCHRONOUS_NON_BLOCKING, BULKHEAD, CIRCUIT_BREAKER, FALLBACK, RATE_LIMIT, RETRY, TIMEOUT); diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/FaultToleranceScanner.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/FaultToleranceScanner.java index bca9ef3b1e576..f4105a2f2d516 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/FaultToleranceScanner.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/FaultToleranceScanner.java @@ -31,6 +31,7 @@ import io.smallrye.faulttolerance.api.ExponentialBackoff; import io.smallrye.faulttolerance.api.FibonacciBackoff; import io.smallrye.faulttolerance.api.RateLimit; +import io.smallrye.faulttolerance.api.RetryWhen; import io.smallrye.faulttolerance.autoconfig.FaultToleranceMethod; import io.smallrye.faulttolerance.autoconfig.MethodDescriptor; @@ -80,7 +81,7 @@ boolean hasFTAnnotations(ClassInfo clazz) { void forEachMethod(ClassInfo clazz, Consumer action) { for (MethodInfo method : clazz.methods()) { if (method.name().startsWith("<")) { - // constructors and static inititalizers can't be intercepted + // constructors and static initializers can't be intercepted continue; } if (method.isSynthetic()) { @@ -134,6 +135,7 @@ FaultToleranceMethod createFaultToleranceMethod(ClassInfo beanClass, MethodInfo result.customBackoff = getAnnotation(CustomBackoff.class, method, beanClass, annotationsPresentDirectly); result.exponentialBackoff = getAnnotation(ExponentialBackoff.class, method, beanClass, annotationsPresentDirectly); result.fibonacciBackoff = getAnnotation(FibonacciBackoff.class, method, beanClass, annotationsPresentDirectly); + result.retryWhen = getAnnotation(RetryWhen.class, method, beanClass, annotationsPresentDirectly); result.annotationsPresentDirectly = annotationsPresentDirectly; diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java index 345c8808dc85f..58c7a022dda81 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java @@ -153,6 +153,15 @@ public void build(BuildProducer annotationsTran for (ClassInfo strategy : index.getAllKnownImplementors(DotNames.CUSTOM_BACKOFF_STRATEGY)) { reflectiveClass.produce(ReflectiveClassBuildItem.builder(strategy.name().toString()).methods().build()); } + // Add reflective access to retry predicates + for (AnnotationInstance annotation : index.getAnnotations(DotNames.RETRY_WHEN)) { + for (String memberName : List.of("result", "exception")) { + AnnotationValue member = annotation.value(memberName); + if (member != null) { + reflectiveClass.produce(ReflectiveClassBuildItem.builder(member.asClass().name().toString()).build()); + } + } + } for (DotName annotation : DotNames.FT_ANNOTATIONS) { reflectiveClass.produce(ReflectiveClassBuildItem.builder(annotation.toString()).methods().build()); @@ -350,8 +359,6 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, } } - // since annotation transformations are applied lazily, we can't know - // all transformed `@*Backoff`s and have to rely on Jandex here for (DotName backoffAnnotation : DotNames.BACKOFF_ANNOTATIONS) { for (AnnotationInstance it : index.getAnnotations(backoffAnnotation)) { if (!annotationStore.hasAnnotation(it.target(), DotNames.RETRY)) { @@ -360,6 +367,11 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, } } } + for (AnnotationInstance it : index.getAnnotations(DotNames.RETRY_WHEN)) { + if (!annotationStore.hasAnnotation(it.target(), DotNames.RETRY)) { + exceptions.add(new DefinitionException("@RetryWhen present on '" + it.target() + "', but @Retry is missing")); + } + } if (!exceptions.isEmpty()) { errors.produce(new ValidationPhaseBuildItem.ValidationErrorBuildItem(exceptions)); diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/qwc-fault-tolerance-methods.js b/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/qwc-fault-tolerance-methods.js index 30dfbb9ab9cf9..f45e180b7259b 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/qwc-fault-tolerance-methods.js +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/qwc-fault-tolerance-methods.js @@ -85,6 +85,7 @@ export class QwcFaultToleranceMethods extends LitElement { ${guardedMethod.ExponentialBackoff ? this._renderExponentialBackoff(guardedMethod.ExponentialBackoff) : html``} ${guardedMethod.FibonacciBackoff ? this._renderFibonacciBackoff(guardedMethod.FibonacciBackoff) : html``} ${guardedMethod.CustomBackoff ? this._renderCustomBackoff(guardedMethod.CustomBackoff) : html``} + ${guardedMethod.RetryWhen ? this._renderRetryWhen(guardedMethod.RetryWhen) : html``} ${guardedMethod.Timeout ? this._renderTimeout(guardedMethod.Timeout) : html``} `; @@ -179,6 +180,15 @@ export class QwcFaultToleranceMethods extends LitElement { `; } + _renderRetryWhen(retryWhen) { + return html` + + ↪ + @RetryWhen(result = ${retryWhen.result}, exception = ${retryWhen.exception}) + + `; + } + _renderTimeout(timeout) { return html` @Timeout(${timeout.value} ${timeout.valueUnit}) diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/AsyncNonBlockingService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/AsyncNonBlockingService.java index 143bc0ab6992c..44d2ce505936f 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/AsyncNonBlockingService.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/AsyncNonBlockingService.java @@ -1,7 +1,7 @@ package io.quarkus.smallrye.faulttolerance.test.asynchronous.additional; -import static io.smallrye.faulttolerance.core.util.CompletionStages.failedFuture; import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import java.util.List; import java.util.concurrent.CompletionStage; diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/BlockingService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/BlockingService.java index 079497679b66c..117ed7ab47e5b 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/BlockingService.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/BlockingService.java @@ -1,7 +1,7 @@ package io.quarkus.smallrye.faulttolerance.test.asynchronous.additional; -import static io.smallrye.faulttolerance.core.util.CompletionStages.failedFuture; import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import java.util.List; import java.util.concurrent.CompletionStage; diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/NonblockingService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/NonblockingService.java index 49e7895249086..5e8b403c44dc1 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/NonblockingService.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/additional/NonblockingService.java @@ -1,7 +1,7 @@ package io.quarkus.smallrye.faulttolerance.test.asynchronous.additional; -import static io.smallrye.faulttolerance.core.util.CompletionStages.failedFuture; import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import java.util.List; import java.util.concurrent.CompletionStage; diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/noncompat/NoncompatNonblockingService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/noncompat/NoncompatNonblockingService.java index 9088f96ffe61f..d86232d589f8e 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/noncompat/NoncompatNonblockingService.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/asynchronous/noncompat/NoncompatNonblockingService.java @@ -1,7 +1,7 @@ package io.quarkus.smallrye.faulttolerance.test.asynchronous.noncompat; -import static io.smallrye.faulttolerance.core.util.CompletionStages.failedFuture; import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import java.util.List; import java.util.concurrent.CompletionStage; diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/ratelimit/RateLimitTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/ratelimit/RateLimitTest.java index 27e24c8a764ba..9f487d684ab4e 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/ratelimit/RateLimitTest.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/ratelimit/RateLimitTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import jakarta.inject.Inject; @@ -26,6 +27,7 @@ public void test() { assertEquals(3, rateLimit.hello()); assertEquals(4, rateLimit.hello()); assertEquals(5, rateLimit.hello()); - assertThrows(RateLimitException.class, () -> rateLimit.hello()); + RateLimitException rateLimitException = assertThrows(RateLimitException.class, () -> rateLimit.hello()); + assertTrue(rateLimitException.getRetryAfterMillis() > 0); } } diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsIllegalArgumentException.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsIllegalArgumentException.java new file mode 100644 index 0000000000000..db978033f0c39 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsIllegalArgumentException.java @@ -0,0 +1,10 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import java.util.function.Predicate; + +public class IsIllegalArgumentException implements Predicate { + @Override + public boolean test(Throwable throwable) { + return throwable instanceof IllegalArgumentException; + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsNull.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsNull.java new file mode 100644 index 0000000000000..4aa61be73387e --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/IsNull.java @@ -0,0 +1,10 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import java.util.function.Predicate; + +public class IsNull implements Predicate { + @Override + public boolean test(Object o) { + return o == null; + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionService.java new file mode 100644 index 0000000000000..bacc0907a2cf0 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionService.java @@ -0,0 +1,15 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.eclipse.microprofile.faulttolerance.Retry; + +import io.smallrye.faulttolerance.api.RetryWhen; + +@ApplicationScoped +public class RetryOnAndRetryWhenExceptionService { + @Retry(retryOn = IllegalStateException.class) + @RetryWhen(exception = IsIllegalArgumentException.class) + public void hello() { + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionTest.java new file mode 100644 index 0000000000000..efed54c502657 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnAndRetryWhenExceptionTest.java @@ -0,0 +1,27 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.enterprise.inject.spi.DeploymentException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class RetryOnAndRetryWhenExceptionTest { + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RetryOnAndRetryWhenExceptionService.class, IsIllegalArgumentException.class)) + .assertException(e -> { + assertEquals(DeploymentException.class, e.getClass()); + assertTrue(e.getMessage().contains("Invalid @RetryWhen.exception")); + assertTrue(e.getMessage().contains("must not be combined with @Retry.retryOn")); + }); + + @Test + public void test() { + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodService.java new file mode 100644 index 0000000000000..1527fe421d866 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodService.java @@ -0,0 +1,16 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import jakarta.enterprise.context.Dependent; + +import org.eclipse.microprofile.faulttolerance.Retry; + +import io.smallrye.faulttolerance.api.RetryWhen; + +@Dependent +@Retry +public class RetryOnClassRetryWhenOnMethodService { + @RetryWhen + public void hello() { + throw new IllegalArgumentException(); + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodTest.java new file mode 100644 index 0000000000000..3058e8bff2196 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnClassRetryWhenOnMethodTest.java @@ -0,0 +1,27 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.enterprise.inject.spi.DefinitionException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class RetryOnClassRetryWhenOnMethodTest { + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RetryOnClassRetryWhenOnMethodService.class)) + .assertException(e -> { + assertEquals(DefinitionException.class, e.getClass()); + assertTrue(e.getMessage().contains("@RetryWhen present")); + assertTrue(e.getMessage().contains("@Retry is missing")); + }); + + @Test + public void test() { + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassService.java new file mode 100644 index 0000000000000..bb1141d02fff6 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassService.java @@ -0,0 +1,16 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import jakarta.enterprise.context.Dependent; + +import org.eclipse.microprofile.faulttolerance.Retry; + +import io.smallrye.faulttolerance.api.RetryWhen; + +@Dependent +@RetryWhen +public class RetryOnMethodRetryWhenOnClassService { + @Retry + public void hello() { + throw new IllegalArgumentException(); + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassTest.java new file mode 100644 index 0000000000000..feabd09a9d954 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryOnMethodRetryWhenOnClassTest.java @@ -0,0 +1,27 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.enterprise.inject.spi.DefinitionException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class RetryOnMethodRetryWhenOnClassTest { + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RetryOnMethodRetryWhenOnClassService.class)) + .assertException(e -> { + assertEquals(DefinitionException.class, e.getClass()); + assertTrue(e.getMessage().contains("@RetryWhen present")); + assertTrue(e.getMessage().contains("@Retry is missing")); + }); + + @Test + public void test() { + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionService.java new file mode 100644 index 0000000000000..a8b0a7756e7af --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionService.java @@ -0,0 +1,31 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.eclipse.microprofile.faulttolerance.Retry; + +import io.smallrye.faulttolerance.api.RetryWhen; + +@ApplicationScoped +public class RetryWhenResultAndExceptionService { + private final AtomicInteger attempts = new AtomicInteger(); + + @Retry + @RetryWhen(result = IsNull.class, exception = IsIllegalArgumentException.class) + public String hello() { + int current = attempts.incrementAndGet(); + if (current == 1) { + return null; + } else if (current == 2) { + throw new IllegalArgumentException(); + } else { + return "hello"; + } + } + + public AtomicInteger getAttempts() { + return attempts; + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionTest.java new file mode 100644 index 0000000000000..024c09293151a --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/retry/when/RetryWhenResultAndExceptionTest.java @@ -0,0 +1,26 @@ +package io.quarkus.smallrye.faulttolerance.test.retry.when; + +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class RetryWhenResultAndExceptionTest { + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RetryWhenResultAndExceptionService.class, IsNull.class, IsIllegalArgumentException.class)); + + @Inject + RetryWhenResultAndExceptionService service; + + @Test + public void test() { + assertThat(service.hello()).isEqualTo("hello"); + assertThat(service.getAttempts()).hasValue(3); + } +} diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java index f1481dc59cfde..78824953316c2 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java @@ -41,7 +41,7 @@ public void createFaultToleranceOperation(List ftMethods) if (error instanceof DeploymentException) { throw (DeploymentException) error; } else { - throw new DeploymentException(allExceptions.get(0)); + throw new DeploymentException(error); } } else { StringBuilder message = new StringBuilder("Found " + allExceptions.size() + " deployment problems: "); diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/devui/FaultToleranceJsonRpcService.java b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/devui/FaultToleranceJsonRpcService.java index 77014a969da4e..4362f1509f2e2 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/devui/FaultToleranceJsonRpcService.java +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/devui/FaultToleranceJsonRpcService.java @@ -22,6 +22,7 @@ import io.smallrye.faulttolerance.api.ExponentialBackoff; import io.smallrye.faulttolerance.api.FibonacciBackoff; import io.smallrye.faulttolerance.api.RateLimit; +import io.smallrye.faulttolerance.api.RetryWhen; import io.smallrye.faulttolerance.config.FaultToleranceOperation; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -127,6 +128,11 @@ private JsonObject convert(FaultToleranceOperation operation) { result.put(CustomBackoff.class.getSimpleName(), new JsonObject() .put("value", operation.getCustomBackoff().value().getName())); } + if (operation.hasRetryWhen()) { + result.put(RetryWhen.class.getSimpleName(), new JsonObject() + .put("result", operation.getRetryWhen().result().getName()) + .put("exception", operation.getRetryWhen().exception().getName())); + } if (operation.hasTimeout()) { result.put(Timeout.class.getSimpleName(), new JsonObject() .put("value", operation.getTimeout().value())