diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 4e5bc32b759c5..cb7d4f28cf7b5 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -69,7 +69,7 @@ 3.0.0 3.5.0 4.7.0 - 2.2.0 + 2.3.0 2.1.2 2.1.1 4.0.1 diff --git a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/ServiceConfiguration.java b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/ServiceConfiguration.java index a5d170359a1a4..7ef7b23f3f9ef 100644 --- a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/ServiceConfiguration.java +++ b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/ServiceConfiguration.java @@ -1,19 +1,23 @@ package io.quarkus.stork; +import java.util.Optional; + import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; @ConfigGroup -public class ServiceConfiguration { +public interface ServiceConfiguration { /** * ServiceDiscovery configuration for the service */ - @ConfigItem - public StorkServiceDiscoveryConfiguration serviceDiscovery; + StorkServiceDiscoveryConfiguration serviceDiscovery(); /** * LoadBalancer configuration for the service */ - @ConfigItem - public StorkLoadBalancerConfiguration loadBalancer; + StorkLoadBalancerConfiguration loadBalancer(); + + /** + * ServiceRegistrar configuration for the service + */ + Optional serviceRegistrar(); } diff --git a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfigUtil.java b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfigUtil.java index d6f12a67cae29..17671e5a88d51 100644 --- a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfigUtil.java +++ b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfigUtil.java @@ -11,17 +11,23 @@ public class StorkConfigUtil { public static List toStorkServiceConfig(StorkConfiguration storkConfiguration) { List storkServicesConfigs = new ArrayList<>(); - Set servicesConfigs = storkConfiguration.serviceConfiguration.keySet(); + Set servicesConfigs = storkConfiguration.serviceConfiguration().keySet(); SimpleServiceConfig.Builder builder = new SimpleServiceConfig.Builder(); for (String serviceName : servicesConfigs) { builder.setServiceName(serviceName); - ServiceConfiguration serviceConfiguration = storkConfiguration.serviceConfiguration.get(serviceName); + ServiceConfiguration serviceConfiguration = storkConfiguration.serviceConfiguration().get(serviceName); SimpleServiceConfig.SimpleServiceDiscoveryConfig storkServiceDiscoveryConfig = new SimpleServiceConfig.SimpleServiceDiscoveryConfig( - serviceConfiguration.serviceDiscovery.type, serviceConfiguration.serviceDiscovery.params); + serviceConfiguration.serviceDiscovery().type(), serviceConfiguration.serviceDiscovery().params()); builder = builder.setServiceDiscovery(storkServiceDiscoveryConfig); SimpleServiceConfig.SimpleLoadBalancerConfig loadBalancerConfig = new SimpleServiceConfig.SimpleLoadBalancerConfig( - serviceConfiguration.loadBalancer.type, serviceConfiguration.loadBalancer.parameters); + serviceConfiguration.loadBalancer().type(), serviceConfiguration.loadBalancer().parameters()); builder.setLoadBalancer(loadBalancerConfig); + if (serviceConfiguration.serviceRegistrar().isPresent()) { + SimpleServiceConfig.SimpleServiceRegistrarConfig serviceRegistrarConfig = new SimpleServiceConfig.SimpleServiceRegistrarConfig( + serviceConfiguration.serviceRegistrar().get().type(), + serviceConfiguration.serviceRegistrar().get().parameters()); + builder.setServiceRegistrar(serviceRegistrarConfig); + } storkServicesConfigs.add(builder.build()); } return storkServicesConfigs; diff --git a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfiguration.java b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfiguration.java index 9a4b2cca0cfd2..cd70cd8c584ab 100644 --- a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfiguration.java +++ b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkConfiguration.java @@ -4,22 +4,24 @@ import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithParentName; /** * Stork configuration root. */ +@ConfigMapping(prefix = "quarkus.stork") @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public class StorkConfiguration { +public interface StorkConfiguration { /** - * ServiceDiscovery configuration for the service + * Configuration for the service */ - @ConfigItem(name = ConfigItem.PARENT) + @WithParentName @ConfigDocSection @ConfigDocMapKey("service-name") - public Map serviceConfiguration; + Map serviceConfiguration(); } diff --git a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkLoadBalancerConfiguration.java b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkLoadBalancerConfiguration.java index 5b51b7f105ba3..3faeee1decab9 100644 --- a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkLoadBalancerConfiguration.java +++ b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkLoadBalancerConfiguration.java @@ -3,25 +3,26 @@ import java.util.Map; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithParentName; @ConfigGroup -public class StorkLoadBalancerConfiguration { +public interface StorkLoadBalancerConfiguration { /** * Configures load balancer type, e.g. "round-robin". * A LoadBalancerProvider for the type has to be available * */ - @ConfigItem(defaultValue = "round-robin") - public String type; + @WithDefault(value = "round-robin") + String type(); /** * Load Balancer parameters. * Check the documentation of the selected load balancer type for available parameters * */ - @ConfigItem(name = ConfigItem.PARENT) - public Map parameters; + @WithParentName + Map parameters(); } diff --git a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceDiscoveryConfiguration.java b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceDiscoveryConfiguration.java index f415c961b3ae7..342e5992b0a86 100644 --- a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceDiscoveryConfiguration.java +++ b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceDiscoveryConfiguration.java @@ -3,25 +3,24 @@ import java.util.Map; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithParentName; @ConfigGroup -public class StorkServiceDiscoveryConfiguration { +public interface StorkServiceDiscoveryConfiguration { /** * Configures the service discovery type, e.g. "consul". * ServiceDiscoveryProvider for the type has to be available * */ - @ConfigItem - public String type; + String type(); /** * ServiceDiscovery parameters. * Check the documentation of the selected service discovery type for available parameters. * */ - @ConfigItem(name = ConfigItem.PARENT) - public Map params; + @WithParentName + Map params(); } diff --git a/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceRegistrarConfiguration.java b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceRegistrarConfiguration.java new file mode 100644 index 0000000000000..cae160b047c2f --- /dev/null +++ b/extensions/smallrye-stork/runtime/src/main/java/io/quarkus/stork/StorkServiceRegistrarConfiguration.java @@ -0,0 +1,27 @@ +package io.quarkus.stork; + +import java.util.Map; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.smallrye.config.WithParentName; + +@ConfigGroup +public interface StorkServiceRegistrarConfiguration { + + /** + * Configures service registrar type, e.g. "consul". + * A ServiceRegistrarProvider for the type has to be available + * + */ + String type(); + + /** + * Service Registrar parameters. + * Check the documentation of the selected registrar type for available parameters + * + */ + // @ConfigItem(name = ConfigItem.PARENT) + @WithParentName + Map parameters(); + +} diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index d2e4485db085f..71b6ea7cc2856 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -68,7 +68,7 @@ 5.3.0 1.0.0.Final 2.15.2 - 2.1.0 + 2.3.0 3.0.2 3.0.3 3.0.0 diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 7495c1b2a01cc..7f2e5546f937f 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -308,6 +308,7 @@ smallrye-graphql smallrye-graphql-client smallrye-opentracing + smallrye-stork-registration jpa-without-entity quartz redis-client diff --git a/integration-tests/smallrye-stork-registration/pom.xml b/integration-tests/smallrye-stork-registration/pom.xml new file mode 100644 index 0000000000000..10cbca86a070f --- /dev/null +++ b/integration-tests/smallrye-stork-registration/pom.xml @@ -0,0 +1,141 @@ + + + + quarkus-integration-tests-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + quarkus-integration-test-smallrye-stork-registration + Quarkus - Integration Tests - Smallrye Stork Registration + + + + + io.quarkus + quarkus-vertx-http + + + + io.quarkus + quarkus-rest-client-reactive-jackson + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.smallrye.stork + stork-service-discovery-static-list + + + + io.quarkus + quarkus-junit5 + test + + + org.assertj + assertj-core + + + io.rest-assured + rest-assured + test + + + org.awaitility + awaitility + test + + + + + io.quarkus + quarkus-resteasy-reactive-jackson-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-rest-client-reactive-jackson-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-vertx-http-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + src/main/resources + true + + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + + native-image + + + native + + + + native + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + diff --git a/integration-tests/smallrye-stork-registration/src/main/java/org/acme/ClientCallingResource.java b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/ClientCallingResource.java new file mode 100644 index 0000000000000..46110519ad351 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/ClientCallingResource.java @@ -0,0 +1,25 @@ +package org.acme; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import org.eclipse.microprofile.rest.client.inject.RestClient; + +/** + * A frontend API using our REST Client (which uses Stork to locate and select the service instance on each call). + */ +@Path("/api") +public class ClientCallingResource { + + @RestClient + MyServiceClient service; + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String invoke() { + return service.get(); + } + +} diff --git a/integration-tests/smallrye-stork-registration/src/main/java/org/acme/MyServiceClient.java b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/MyServiceClient.java new file mode 100644 index 0000000000000..aeba6019125d3 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/MyServiceClient.java @@ -0,0 +1,22 @@ +package org.acme; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +/** + * The REST Client interface. + * + * Notice the `baseUri`. It uses `stork://` as URL scheme indicating that the called service uses Stork to locate and + * select the service instance. The `my-service` part is the service name. This is used to configure Stork discovery + * and selection in the `application.properties` file. + */ +@RegisterRestClient(baseUri = "stork://my-service") +public interface MyServiceClient { + + @GET + @Produces(MediaType.TEXT_PLAIN) + String get(); +} diff --git a/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/BlueService.java b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/BlueService.java new file mode 100644 index 0000000000000..f209e90dfd910 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/BlueService.java @@ -0,0 +1,27 @@ +package org.acme.services; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.runtime.StartupEvent; +import io.vertx.mutiny.core.Vertx; + +@ApplicationScoped +public class BlueService { + + @ConfigProperty(name = "blue-service-port", defaultValue = "9000") + int port; + + /** + * Start an HTTP server for the blue service. + * + * Note: this method is called on a worker thread, and so it is allowed to block. + */ + public void init(@Observes StartupEvent ev, Vertx vertx) { + vertx.createHttpServer() + .requestHandler(req -> req.response().endAndForget("Hello from Blue!")) + .listenAndAwait(port); + } +} diff --git a/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/RedService.java b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/RedService.java new file mode 100644 index 0000000000000..475ca81eaf3a0 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/RedService.java @@ -0,0 +1,28 @@ + +package org.acme.services; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.runtime.StartupEvent; +import io.vertx.mutiny.core.Vertx; + +@ApplicationScoped +public class RedService { + @ConfigProperty(name = "red-service-port", defaultValue = "9001") + int port; + + /** + * Start an HTTP server for the red service. + * + * Note: this method is called on a worker thread, and so it is allowed to block. + */ + public void init(@Observes StartupEvent ev, Vertx vertx) { + vertx.createHttpServer() + .requestHandler(req -> req.response().endAndForget("Hello from Red!")) + .listenAndAwait(port); + } + +} diff --git a/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/Registration.java b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/Registration.java new file mode 100644 index 0000000000000..a313868eab571 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/main/java/org/acme/services/Registration.java @@ -0,0 +1,31 @@ +package org.acme.services; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.runtime.StartupEvent; +import io.smallrye.stork.Stork; +import io.vertx.mutiny.core.Vertx; + +@ApplicationScoped +public class Registration { + + @ConfigProperty(name = "red-service-port", defaultValue = "9000") + int red; + @ConfigProperty(name = "blue-service-port", defaultValue = "9001") + int blue; + + /** + * Register our two services using static list. + * + * Note: this method is called on a worker thread, and so it is allowed to block. + */ + public void init(@Observes StartupEvent ev, Vertx vertx) { + Stork.getInstance().getService("my-service").getServiceRegistrar().registerServiceInstance("my-service", "localhost", + red); + Stork.getInstance().getService("my-service").getServiceRegistrar().registerServiceInstance("my-service", "localhost", + blue); + } +} diff --git a/integration-tests/smallrye-stork-registration/src/main/resources/application.properties b/integration-tests/smallrye-stork-registration/src/main/resources/application.properties new file mode 100644 index 0000000000000..15a149ec67485 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/main/resources/application.properties @@ -0,0 +1,3 @@ +quarkus.stork.my-service.service-discovery.type=static + +quarkus.stork.my-service.service-registrar.type=static diff --git a/integration-tests/smallrye-stork-registration/src/test/java/org/acme/ClientCallingResourceIT.java b/integration-tests/smallrye-stork-registration/src/test/java/org/acme/ClientCallingResourceIT.java new file mode 100644 index 0000000000000..35a7b5cef2e89 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/test/java/org/acme/ClientCallingResourceIT.java @@ -0,0 +1,8 @@ +package org.acme; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class ClientCallingResourceIT extends ClientCallingResourceTest { + +} diff --git a/integration-tests/smallrye-stork-registration/src/test/java/org/acme/ClientCallingResourceTest.java b/integration-tests/smallrye-stork-registration/src/test/java/org/acme/ClientCallingResourceTest.java new file mode 100644 index 0000000000000..530da75f8fbb6 --- /dev/null +++ b/integration-tests/smallrye-stork-registration/src/test/java/org/acme/ClientCallingResourceTest.java @@ -0,0 +1,24 @@ +package org.acme; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +@QuarkusTest +public class ClientCallingResourceTest { + + @Test + public void test() { + Set bodies = new HashSet<>(); + for (int i = 0; i < 10; i++) { + bodies.add(RestAssured.get("/api").then().statusCode(200).extract().body().asString()); + } + Assertions.assertEquals(2, bodies.size()); + } + +}