diff --git a/pom.xml b/pom.xml index 6dbe33b..fe8a0ad 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,14 @@ io.quarkus quarkus-rest-jackson + + io.quarkus + quarkus-smallrye-stork + + + io.smallrye.stork + stork-service-registration-consul + io.quarkus quarkus-junit diff --git a/src/main/docker-compose/jvm.yml b/src/main/docker-compose/jvm.yml new file mode 100644 index 0000000..53b1818 --- /dev/null +++ b/src/main/docker-compose/jvm.yml @@ -0,0 +1,22 @@ +services: + shikimori-metadata-service: + build: + context: ../../../. + dockerfile: src/main/docker/Dockerfile.jvm + container_name: shikimori-metadata-service + restart: on-failure + networks: + - anyame-consul + deploy: + resources: + limits: + memory: 512M + cpus: "1" + reservations: + memory: 128M + cpus: "0.3" + +networks: + anyame-consul: + name: anyame-consul + external: true diff --git a/src/main/docker-compose/native.yml b/src/main/docker-compose/native.yml new file mode 100644 index 0000000..bbbe8c7 --- /dev/null +++ b/src/main/docker-compose/native.yml @@ -0,0 +1,22 @@ +services: + shikimori-metadata-service: + build: + context: ../../../. + dockerfile: src/main/docker/Dockerfile.native-micro + container_name: shikimori-metadata-service + restart: on-failure + networks: + - anyame-consul + deploy: + resources: + limits: + memory: 512M + cpus: "1" + reservations: + memory: 128M + cpus: "0.3" + +networks: + anyame-consul: + name: anyame-consul + external: true diff --git a/src/main/docker/Dockerfile.jvm b/src/main/docker/Dockerfile.jvm index b491681..7fe95c4 100644 --- a/src/main/docker/Dockerfile.jvm +++ b/src/main/docker/Dockerfile.jvm @@ -80,7 +80,7 @@ # You can find more information about the UBI base runtime images and their configuration here: # https://rh-openjdk.github.io/redhat-openjdk-containers/ ### -FROM registry.access.redhat.com/ubi9/openjdk-25:1.23 +FROM registry.access.redhat.com/ubi9/openjdk-25:1.24 ENV LANGUAGE='en_US:en' diff --git a/src/main/java/com/backend/metadata/shikimori/ApplicationBeanProducer.java b/src/main/java/com/backend/metadata/shikimori/ApplicationBeanProducer.java new file mode 100644 index 0000000..109f6b3 --- /dev/null +++ b/src/main/java/com/backend/metadata/shikimori/ApplicationBeanProducer.java @@ -0,0 +1,30 @@ +package com.backend.metadata.shikimori; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jboss.logging.Logger; + +import io.quarkus.arc.lookup.LookupIfProperty; +import io.vertx.core.Vertx; +import io.vertx.ext.consul.ConsulClient; +import io.vertx.ext.consul.ConsulClientOptions; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +@ApplicationScoped +public class ApplicationBeanProducer { + Logger logger = Logger.getLogger(ApplicationBeanProducer.class); + + @ConfigProperty(name = "consul.host", defaultValue = "consul") + String host; + @ConfigProperty(name = "consul.port", defaultValue = "8500") + int port; + + @Produces + @LookupIfProperty(name = "quarkus.stork.shikimori-search-service.service-registrar.type", stringValue = "consul") + public ConsulClient consulClient(Vertx vertx) { + return ConsulClient.create(vertx, new ConsulClientOptions() + .setHost(host) + .setPort(port)); + } + +} diff --git a/src/main/java/com/backend/metadata/shikimori/ApplicationLifecycle.java b/src/main/java/com/backend/metadata/shikimori/ApplicationLifecycle.java new file mode 100644 index 0000000..c871d55 --- /dev/null +++ b/src/main/java/com/backend/metadata/shikimori/ApplicationLifecycle.java @@ -0,0 +1,56 @@ +package com.backend.metadata.shikimori; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jboss.logging.Logger; + +import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.runtime.StartupEvent; +import io.vertx.ext.consul.ConsulClient; +import io.vertx.ext.consul.ServiceOptions; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Instance; + +@ApplicationScoped +public class ApplicationLifecycle { + + @ConfigProperty(name = "quarkus.application.name") + private String appName; + @ConfigProperty(name = "quarkus.application.port", defaultValue = "8080") + private int port; + + private Logger logger; + private Instance consulClient; + private ScheduledExecutorService executor; + + public ApplicationLifecycle(Logger logger, + Instance consulClient, + ScheduledExecutorService executor) { + this.logger = logger; + this.consulClient = consulClient; + this.executor = executor; + } + + void onStart(@Observes StartupEvent ev) { + if (consulClient.isResolvable()) { + executor.schedule(() -> { + consulClient.get().registerService(new ServiceOptions() + .setPort(port) + .setAddress(appName) + .setName(appName) + .setId(appName), + result -> logger.infof("Service %s-%d registered", appName, port)); + }, 1000, TimeUnit.MILLISECONDS); + } + } + + void onStop(@Observes ShutdownEvent ev) { + if (consulClient.isResolvable()) { + consulClient.get().deregisterService(appName + "-" + port, + result -> logger.infof("Service %s-%d deregistered", appName, port)); + } + } +} diff --git a/src/main/java/com/backend/metadata/shikimori/resource/ShikimoriResource.java b/src/main/java/com/backend/metadata/shikimori/resource/ShikimoriResource.java index bd9c984..b310a2f 100644 --- a/src/main/java/com/backend/metadata/shikimori/resource/ShikimoriResource.java +++ b/src/main/java/com/backend/metadata/shikimori/resource/ShikimoriResource.java @@ -19,6 +19,7 @@ public class ShikimoriResource { } @GET + @Path("/search") public Anime findById(@QueryParam("id") String id) { List result = shikimoriAPI.animes(1, 1, id, null, null); if (result.isEmpty()) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3e99f5e..9d77cb5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,4 @@ -# Shikimori API configuration -shikimori-api/mp-rest/url=https://shikimori.one -shikimori-api/mp-rest/scope=jakarta.inject.Singleton +quarkus.application.name=shikimori-metadata-service + +quarkus.stork.shikimori-search-service.service-registrar.type=consul + diff --git a/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceIT.java b/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceIT.java index 0adde8d..e343459 100644 --- a/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceIT.java +++ b/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceIT.java @@ -3,6 +3,6 @@ package com.backend.metadata.shikimori.service; import io.quarkus.test.junit.QuarkusIntegrationTest; @QuarkusIntegrationTest -class GreetingResourceIT extends GreetingResourceTest { +class GreetingResourceIT { // Execute the same tests but in packaged mode. } diff --git a/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceTest.java b/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceTest.java deleted file mode 100644 index e1e2d04..0000000 --- a/src/test/java/com/backend/metadata/shikimori/service/GreetingResourceTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.backend.metadata.shikimori.service; - -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Test; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.is; - -@QuarkusTest -class GreetingResourceTest { - @Test - void testHelloEndpoint() { - given() - .when().get("/hello") - .then() - .statusCode(200) - .body(is("Hello from Quarkus REST")); - } - -} \ No newline at end of file