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 2ce17873fb303..805878809ebce 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 @@ -56,6 +56,7 @@ import io.quarkus.deployment.recording.RecorderContext; import io.quarkus.gizmo.ClassOutput; import io.quarkus.runtime.metrics.MetricsFactory; +import io.quarkus.smallrye.faulttolerance.deployment.devui.FaultToleranceInfoBuildItem; import io.quarkus.smallrye.faulttolerance.runtime.QuarkusAsyncExecutorProvider; import io.quarkus.smallrye.faulttolerance.runtime.QuarkusExistingCircuitBreakerNames; import io.quarkus.smallrye.faulttolerance.runtime.QuarkusFallbackHandlerProvider; @@ -107,7 +108,7 @@ public void build(BuildProducer annotationsTran AdditionalBeanBuildItem.Builder fallbackHandlersBeans = AdditionalBeanBuildItem.builder() .setDefaultScope(BuiltinScope.DEPENDENT.getName()); for (String fallbackHandler : fallbackHandlers) { - reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, fallbackHandler)); + reflectiveClass.produce(ReflectiveClassBuildItem.builder(fallbackHandler).methods().build()); fallbackHandlersBeans.addBeanClass(fallbackHandler); } beans.produce(fallbackHandlersBeans.build()); @@ -151,11 +152,11 @@ public void build(BuildProducer annotationsTran } // Add reflective access to custom backoff strategies for (ClassInfo strategy : index.getAllKnownImplementors(DotNames.CUSTOM_BACKOFF_STRATEGY)) { - reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, strategy.name().toString())); + reflectiveClass.produce(ReflectiveClassBuildItem.builder(strategy.name().toString()).methods().build()); } for (DotName annotation : DotNames.FT_ANNOTATIONS) { - reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, annotation.toString())); + reflectiveClass.produce(ReflectiveClassBuildItem.builder(annotation.toString()).methods().build()); // also make them bean defining annotations additionalBda.produce(new BeanDefiningAnnotationBuildItem(annotation)); } @@ -252,7 +253,8 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, AnnotationProxyBuildItem annotationProxy, BuildProducer generatedClasses, BuildProducer reflectiveClass, - BuildProducer errors) { + BuildProducer errors, + BuildProducer faultToleranceInfo) { Config config = ConfigProvider.getConfig(); @@ -262,7 +264,7 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, for (String exceptionConfig : exceptionConfigs) { Optional exceptionNames = config.getOptionalValue(exceptionConfig, String[].class); if (exceptionNames.isPresent()) { - reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, exceptionNames.get())); + reflectiveClass.produce(ReflectiveClassBuildItem.builder(exceptionNames.get()).build()); } } @@ -289,7 +291,7 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, Optional exceptionNames = config.getOptionalValue(beanClass.name().toString() + "/" + exceptionConfig, String[].class); if (exceptionNames.isPresent()) { - reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, exceptionNames.get())); + reflectiveClass.produce(ReflectiveClassBuildItem.builder(exceptionNames.get()).build()); } } @@ -314,7 +316,7 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, Optional exceptionNames = config.getOptionalValue(beanClass.name().toString() + "/" + method.name() + "/" + exceptionConfig, String[].class); if (exceptionNames.isPresent()) { - reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, exceptionNames.get())); + reflectiveClass.produce(ReflectiveClassBuildItem.builder(exceptionNames.get()).build()); } } } @@ -368,6 +370,9 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, } recorder.initExistingCircuitBreakerNames(existingCircuitBreakerNames.keySet()); + + // dev UI + faultToleranceInfo.produce(new FaultToleranceInfoBuildItem(ftMethods.size())); } @BuildStep diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/devui/FaultToleranceDevUIProcessor.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/devui/FaultToleranceDevUIProcessor.java new file mode 100644 index 0000000000000..129e0c204ef5a --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/devui/FaultToleranceDevUIProcessor.java @@ -0,0 +1,30 @@ +package io.quarkus.smallrye.faulttolerance.deployment.devui; + +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; +import io.quarkus.smallrye.faulttolerance.runtime.devui.FaultToleranceJsonRpcService; + +public class FaultToleranceDevUIProcessor { + private static final String NAME = "SmallRye Fault Tolerance"; + + @BuildStep(onlyIf = IsDevelopment.class) + CardPageBuildItem cardPage(FaultToleranceInfoBuildItem faultToleranceInfo) { + CardPageBuildItem pageBuildItem = new CardPageBuildItem(NAME); + + pageBuildItem.addPage(Page.webComponentPageBuilder() + .title("Guarded Methods") + .icon("font-awesome-solid:life-ring") + .componentLink("qwc-fault-tolerance-methods.js") + .staticLabel("" + faultToleranceInfo.getGuardedMethods())); + + return pageBuildItem; + } + + @BuildStep(onlyIf = IsDevelopment.class) + JsonRPCProvidersBuildItem jsonRPCService() { + return new JsonRPCProvidersBuildItem(NAME, FaultToleranceJsonRpcService.class); + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/devui/FaultToleranceInfoBuildItem.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/devui/FaultToleranceInfoBuildItem.java new file mode 100644 index 0000000000000..1a0dc0f0d6b33 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/devui/FaultToleranceInfoBuildItem.java @@ -0,0 +1,15 @@ +package io.quarkus.smallrye.faulttolerance.deployment.devui; + +import io.quarkus.builder.item.SimpleBuildItem; + +public final class FaultToleranceInfoBuildItem extends SimpleBuildItem { + private final int guardedMethods; + + public FaultToleranceInfoBuildItem(int guardedMethods) { + this.guardedMethods = guardedMethods; + } + + public int getGuardedMethods() { + return guardedMethods; + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-templates/ft-operations.html b/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-templates/ft-operations.html index b6367a8a54252..b5dad1e58494d 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-templates/ft-operations.html +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-templates/ft-operations.html @@ -66,6 +66,10 @@
  • @Asynchronous
  • {/if} + {#if ftOperation.asynchronousNonBlocking} +
  • @AsynchronousNonBlocking
  • + {/if} + {#if ftOperation.blocking}
  • @Blocking
  • {/if} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/smallrye-fault-tolerance/qwc-fault-tolerance-methods.js b/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/smallrye-fault-tolerance/qwc-fault-tolerance-methods.js new file mode 100644 index 0000000000000..55cb27e830b4b --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/resources/dev-ui/smallrye-fault-tolerance/qwc-fault-tolerance-methods.js @@ -0,0 +1,198 @@ +import {css, html, LitElement} from 'lit'; +import {until} from 'lit/directives/until.js'; +import {JsonRpc} from 'jsonrpc'; +import '@vaadin/grid'; +import {columnBodyRenderer} from '@vaadin/grid/lit.js'; +import '@vaadin/vertical-layout'; + +export class QwcFaultToleranceMethods extends LitElement { + jsonRpc = new JsonRpc('SmallRye Fault Tolerance'); + + static styles = css` + vaadin-grid { + height: 100%; + padding-bottom: 10px; + } + + .method { + color: var(--lumo-primary-text-color); + } + `; + + static properties = { + _guardedMethods: {state: true}, + }; + + connectedCallback() { + super.connectedCallback(); + this._refresh(); + } + + render() { + return html`${until(this._renderGuardedMethods(), html`Loading guarded methods...`)}`; + } + + _renderGuardedMethods() { + if (this._guardedMethods) { + return html` + + + + + + + + + + + `; + } + } + + _renderBeanClass(guardedMethod) { + return html` + ${guardedMethod.beanClass} + `; + } + + _renderMethodName(guardedMethod) { + return html` + ${guardedMethod.method}() + `; + } + + _renderStrategies(guardedMethod) { + return html` + + ${guardedMethod.ApplyFaultTolerance ? this._renderApplyFaultTolerance(guardedMethod.ApplyFaultTolerance) : html``} + ${guardedMethod.Asynchronous ? html`@Asynchronous` : html``} + ${guardedMethod.AsynchronousNonBlocking ? html`@AsynchronousNonBlocking` : html``} + ${guardedMethod.Blocking ? html`@Blocking` : html``} + ${guardedMethod.NonBlocking ? html`@NonBlocking` : html``} + ${guardedMethod.Bulkhead ? this._renderBulkhead(guardedMethod.Bulkhead) : html``} + ${guardedMethod.CircuitBreaker ? this._renderCircuitBreaker(guardedMethod.CircuitBreaker) : html``} + ${guardedMethod.CircuitBreakerName ? this._renderCircuitBreakerName(guardedMethod.CircuitBreakerName) : html``} + ${guardedMethod.Fallback ? this._renderFallback(guardedMethod.Fallback) : html``} + ${guardedMethod.RateLimit ? this._renderRateLimit(guardedMethod.RateLimit) : html``} + ${guardedMethod.Retry ? this._renderRetry(guardedMethod.Retry) : html``} + ${guardedMethod.ExponentialBackoff ? this._renderExponentialBackoff(guardedMethod.ExponentialBackoff) : html``} + ${guardedMethod.FibonacciBackoff ? this._renderFibonacciBackoff(guardedMethod.FibonacciBackoff) : html``} + ${guardedMethod.CustomBackoff ? this._renderCustomBackoff(guardedMethod.CustomBackoff) : html``} + ${guardedMethod.Timeout ? this._renderTimeout(guardedMethod.Timeout) : html``} + + `; + } + + _renderApplyFaultTolerance(applyFaultTolerance) { + return html` + @ApplyFaultTolerance("${applyFaultTolerance.value}") + `; + } + + _renderBulkhead(bulkhead) { + return html` + @Bulkhead(value = ${bulkhead.value}, waitingTaskQueue = ${bulkhead.waitingTaskQueue}) + `; + } + + _renderCircuitBreaker(circuitBreaker) { + return html` + @CircuitBreaker(delay = ${circuitBreaker.delay} ${circuitBreaker.delayUnit}, + requestVolumeThreshold = ${circuitBreaker.requestVolumeThreshold}, + failureRatio = ${circuitBreaker.failureRatio}, + successThreshold = ${circuitBreaker.successThreshold}, + failOn = ${this._renderArray(circuitBreaker.failOn)}, + skipOn = ${this._renderArray(circuitBreaker.skipOn)}) + `; + } + + _renderCircuitBreakerName(circuitBreakerName) { + return html` + + ↪ + @CircuitBreakerName("${circuitBreakerName.value}") + + `; + } + + _renderFallback(fallback) { + return html` + @Fallback(value = ${fallback.value}, + fallbackMethod = "${fallback.fallbackMethod}", + applyOn = ${this._renderArray(fallback.applyOn)}, + skipOn = ${this._renderArray(fallback.skipOn)}) + `; + } + + _renderRateLimit(rateLimit) { + return html` + @RateLimit(value = ${rateLimit.value}, + window = ${rateLimit.window} ${rateLimit.windowUnit}, + minSpacing = ${rateLimit.minSpacing} ${rateLimit.minSpacingUnit}, + type = ${rateLimit.type}) + `; + } + + _renderRetry(retry) { + return html` + @Retry(maxRetries = ${retry.maxRetries}, + delay = ${retry.delay} ${retry.delayUnit}, + maxDuration = ${retry.maxDuration} ${retry.maxDurationUnit}, + jitter = ${retry.jitter} ${retry.jitterUnit}, + retryOn = ${this._renderArray(retry.retryOn)}, + abortOn = ${this._renderArray(retry.abortOn)}) + `; + } + + _renderExponentialBackoff(exponentialBackoff) { + return html` + + ↪ + @ExponentialBackoff(factor = ${exponentialBackoff.factor}, + maxDelay = ${exponentialBackoff.maxDelay} ${exponentialBackoff.maxDelayUnit}) + + `; + } + + _renderFibonacciBackoff(fibonacciBackoff) { + return html` + + ↪ + @FibonacciBackoff(maxDelay = ${fibonacciBackoff.maxDelay} ${fibonacciBackoff.maxDelayUnit}) + + `; + } + + _renderCustomBackoff(customBackoff) { + return html` + + ↪ + @CustomBackoff(${customBackoff.value}) + + `; + } + + _renderTimeout(timeout) { + return html` + @Timeout(${timeout.value} ${timeout.valueUnit}) + `; + } + + _renderArray(array) { + return array ? html`[${array.join(', ')}]` : html`[]`; + } + + _refresh() { + this.jsonRpc.getGuardedMethods().then(guardedMethods => { + this._guardedMethods = guardedMethods.result; + }); + } +} + +customElements.define('qwc-fault-tolerance-methods', QwcFaultToleranceMethods); diff --git a/extensions/smallrye-fault-tolerance/runtime/pom.xml b/extensions/smallrye-fault-tolerance/runtime/pom.xml index 43c7e01478e65..7d896e6df4ef0 100644 --- a/extensions/smallrye-fault-tolerance/runtime/pom.xml +++ b/extensions/smallrye-fault-tolerance/runtime/pom.xml @@ -74,6 +74,12 @@ smallrye-fault-tolerance-mutiny + + + io.vertx + vertx-core + true + diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java index 06769240943e4..2f8ccb2fa9fb2 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java @@ -49,7 +49,7 @@ private FaultToleranceOperation createAtRuntime(CacheKey key) { return FaultToleranceOperation.create(FaultToleranceMethods.create(key.beanClass, key.method)); } - Map getOperationCache() { + public Map getOperationCache() { return operationCache; } 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 new file mode 100644 index 0000000000000..77014a969da4e --- /dev/null +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/devui/FaultToleranceJsonRpcService.java @@ -0,0 +1,146 @@ +package io.quarkus.smallrye.faulttolerance.runtime.devui; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.microprofile.faulttolerance.Asynchronous; +import org.eclipse.microprofile.faulttolerance.Bulkhead; +import org.eclipse.microprofile.faulttolerance.CircuitBreaker; +import org.eclipse.microprofile.faulttolerance.Fallback; +import org.eclipse.microprofile.faulttolerance.Retry; +import org.eclipse.microprofile.faulttolerance.Timeout; + +import io.quarkus.arc.Arc; +import io.quarkus.smallrye.faulttolerance.runtime.QuarkusFaultToleranceOperationProvider; +import io.smallrye.common.annotation.Blocking; +import io.smallrye.common.annotation.NonBlocking; +import io.smallrye.faulttolerance.api.ApplyFaultTolerance; +import io.smallrye.faulttolerance.api.AsynchronousNonBlocking; +import io.smallrye.faulttolerance.api.CircuitBreakerName; +import io.smallrye.faulttolerance.api.CustomBackoff; +import io.smallrye.faulttolerance.api.ExponentialBackoff; +import io.smallrye.faulttolerance.api.FibonacciBackoff; +import io.smallrye.faulttolerance.api.RateLimit; +import io.smallrye.faulttolerance.config.FaultToleranceOperation; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; + +public class FaultToleranceJsonRpcService { + public JsonArray getGuardedMethods() { + QuarkusFaultToleranceOperationProvider provider = Arc.container() + .select(QuarkusFaultToleranceOperationProvider.class).get(); + List operations = new ArrayList<>(provider.getOperationCache().values()); + operations.sort(Comparator.comparing(FaultToleranceOperation::getName)); + + JsonArray result = new JsonArray(); + for (FaultToleranceOperation operation : operations) { + operation.materialize(); + result.add(convert(operation)); + } + return result; + } + + private JsonObject convert(FaultToleranceOperation operation) { + JsonObject result = new JsonObject(); + + result.put("beanClass", operation.getBeanClass().getName()); + result.put("method", operation.getMethodDescriptor().name); + + if (operation.hasApplyFaultTolerance()) { + result.put(ApplyFaultTolerance.class.getSimpleName(), new JsonObject() + .put("value", operation.getApplyFaultTolerance().value())); + } + + if (operation.hasAsynchronous()) { + result.put(Asynchronous.class.getSimpleName(), new JsonObject()); + } + if (operation.hasAsynchronousNonBlocking()) { + result.put(AsynchronousNonBlocking.class.getSimpleName(), new JsonObject()); + } + if (operation.hasBlocking()) { + result.put(Blocking.class.getSimpleName(), new JsonObject()); + } + if (operation.hasNonBlocking()) { + result.put(NonBlocking.class.getSimpleName(), new JsonObject()); + } + + if (operation.hasBulkhead()) { + result.put(Bulkhead.class.getSimpleName(), new JsonObject() + .put("value", operation.getBulkhead().value()) + .put("waitingTaskQueue", operation.getBulkhead().waitingTaskQueue())); + } + if (operation.hasCircuitBreaker()) { + result.put(CircuitBreaker.class.getSimpleName(), new JsonObject() + .put("delay", operation.getCircuitBreaker().delay()) + .put("delayUnit", operation.getCircuitBreaker().delayUnit()) + .put("requestVolumeThreshold", operation.getCircuitBreaker().requestVolumeThreshold()) + .put("failureRatio", operation.getCircuitBreaker().failureRatio()) + .put("successThreshold", operation.getCircuitBreaker().successThreshold()) + .put("failOn", convert(operation.getCircuitBreaker().failOn())) + .put("skipOn", convert(operation.getCircuitBreaker().skipOn()))); + } + if (operation.hasCircuitBreakerName()) { + result.put(CircuitBreakerName.class.getSimpleName(), new JsonObject() + .put("value", operation.getCircuitBreakerName().value())); + } + if (operation.hasFallback()) { + result.put(Fallback.class.getSimpleName(), new JsonObject() + .put("value", operation.getFallback().value().getName()) + .put("fallbackMethod", operation.getFallback().fallbackMethod()) + .put("applyOn", convert(operation.getFallback().applyOn())) + .put("skipOn", convert(operation.getFallback().skipOn()))); + } + if (operation.hasRateLimit()) { + result.put(RateLimit.class.getSimpleName(), new JsonObject() + .put("value", operation.getRateLimit().value()) + .put("window", operation.getRateLimit().window()) + .put("windowUnit", operation.getRateLimit().windowUnit()) + .put("minSpacing", operation.getRateLimit().minSpacing()) + .put("minSpacingUnit", operation.getRateLimit().minSpacingUnit()) + .put("type", operation.getRateLimit().type())); + } + if (operation.hasRetry()) { + result.put(Retry.class.getSimpleName(), new JsonObject() + .put("maxRetries", operation.getRetry().maxRetries()) + .put("delay", operation.getRetry().delay()) + .put("delayUnit", operation.getRetry().delayUnit()) + .put("maxDuration", operation.getRetry().maxDuration()) + .put("maxDurationUnit", operation.getRetry().durationUnit()) + .put("jitter", operation.getRetry().jitter()) + .put("jitterUnit", operation.getRetry().jitterDelayUnit()) + .put("retryOn", convert(operation.getRetry().retryOn())) + .put("abortOn", convert(operation.getRetry().abortOn()))); + } + if (operation.hasExponentialBackoff()) { + result.put(ExponentialBackoff.class.getSimpleName(), new JsonObject() + .put("factor", operation.getExponentialBackoff().factor()) + .put("maxDelay", operation.getExponentialBackoff().maxDelay()) + .put("maxDelayUnit", operation.getExponentialBackoff().maxDelayUnit())); + } + if (operation.hasFibonacciBackoff()) { + result.put(FibonacciBackoff.class.getSimpleName(), new JsonObject() + .put("maxDelay", operation.getFibonacciBackoff().maxDelay()) + .put("maxDelayUnit", operation.getFibonacciBackoff().maxDelayUnit())); + } + if (operation.hasCustomBackoff()) { + result.put(CustomBackoff.class.getSimpleName(), new JsonObject() + .put("value", operation.getCustomBackoff().value().getName())); + } + if (operation.hasTimeout()) { + result.put(Timeout.class.getSimpleName(), new JsonObject() + .put("value", operation.getTimeout().value()) + .put("valueUnit", operation.getTimeout().unit())); + } + + return result; + } + + private static JsonArray convert(Class[] classes) { + JsonArray result = new JsonArray(); + for (Class clazz : classes) { + result.add(clazz.getName()); + } + return result; + } +} diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 09fa699d5f661..3862c32273158 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -3,12 +3,16 @@ artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Fault Tolerance" metadata: keywords: - - "smallrye-fault-tolerance" - "fault-tolerance" + - "smallrye-fault-tolerance" - "microprofile-fault-tolerance" - - "circuit-breaker" - "bulkhead" - guide: "https://quarkus.io/guides/microprofile-fault-tolerance" + - "circuit-breaker" + - "fallback" + - "rate-limit" + - "retry" + - "timeout" + guide: "https://quarkus.io/guides/smallrye-fault-tolerance" categories: - "cloud" status: "stable"