From 6af9437cf3c54628e873fdbcf1fced723f6e3e94 Mon Sep 17 00:00:00 2001 From: Daniel Kec Date: Tue, 6 Dec 2022 00:54:58 +0100 Subject: [PATCH 1/7] CRaC K8s POC Workaround for: Error (criu/cr-dump.c:203): 18 has rseq but kernel lacks get_rseq_conf feature Signed-off-by: Daniel Kec --- dependencies/pom.xml | 6 + examples/crac/Dockerfile.crac | 43 +++++++ examples/crac/Dockerfile.native_image | 17 +++ examples/crac/README.md | 41 +++++++ examples/crac/app.yaml | 64 ++++++++++ examples/crac/deploy-minikube.sh | 28 +++++ examples/crac/pom.xml | 88 ++++++++++++++ examples/crac/runtimeCRaC.sh | 45 +++++++ .../helloworld/implicit/AnotherResource.java | 107 +++++++++++++++++ .../implicit/HelloWorldResource.java | 113 ++++++++++++++++++ .../implicit/cdi/LoggerQualifier.java | 34 ++++++ .../helloworld/implicit/cdi/RequestId.java | 33 +++++ .../implicit/cdi/RequestIdProducer.java | 27 +++++ .../implicit/cdi/ResourceProducer.java | 54 +++++++++ .../helloworld/implicit/cdi/package-info.java | 20 ++++ .../helloworld/implicit/package-info.java | 20 ++++ .../src/main/resources/META-INF/beans.xml | 25 ++++ .../META-INF/microprofile-config.properties | 27 +++++ .../src/main/resources/logging.properties | 20 ++++ .../implicit/ImplicitHelloWorldTest.java | 59 +++++++++ microprofile/server/pom.xml | 4 + .../server/ServerCdiExtension.java | 46 ++++++- .../server/src/main/java/module-info.java | 1 + 23 files changed, 920 insertions(+), 2 deletions(-) create mode 100644 examples/crac/Dockerfile.crac create mode 100644 examples/crac/Dockerfile.native_image create mode 100644 examples/crac/README.md create mode 100644 examples/crac/app.yaml create mode 100644 examples/crac/deploy-minikube.sh create mode 100644 examples/crac/pom.xml create mode 100644 examples/crac/runtimeCRaC.sh create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java create mode 100644 examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java create mode 100644 examples/crac/src/main/resources/META-INF/beans.xml create mode 100644 examples/crac/src/main/resources/META-INF/microprofile-config.properties create mode 100644 examples/crac/src/main/resources/logging.properties create mode 100644 examples/crac/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java diff --git a/dependencies/pom.xml b/dependencies/pom.xml index efe38f1ef9d..2a5165f48e8 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -59,6 +59,7 @@ 2.9.0 1.60.0 32.0.1-jre + 0.1.3 2.2.220 1.3 4.3.1 @@ -812,6 +813,11 @@ jakarta.validation-api ${version.lib.jakarta.validation-api} + + io.github.crac + org-crac + ${version.lib.crac} + com.h2database h2 diff --git a/examples/crac/Dockerfile.crac b/examples/crac/Dockerfile.crac new file mode 100644 index 00000000000..e239f63fb32 --- /dev/null +++ b/examples/crac/Dockerfile.crac @@ -0,0 +1,43 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +FROM debian:stretch-slim as ubuntu-crac + +WORKDIR /usr/share + +ARG CHECKPOINT_DIR + +ENV CRAC_ARTEFACT=openjdk-17-crac+3_linux-x64 +ENV JAVA_HOME=/usr/share/$CRAC_ARTEFACT +ENV CR_DIR=${CONT_IMG_VER:-/crac-checkpoint/cr} + +# Install CRaC +RUN apt-get -qq update && apt-get install -y wget +RUN wget https://github.com/CRaC/openjdk-builds/releases/download/17-crac%2B3/$CRAC_ARTEFACT.tar.gz \ +&& tar zxf $CRAC_ARTEFACT.tar.gz \ +&& ln -s $JAVA_HOME/bin/java /bin/ + +FROM ubuntu-crac +WORKDIR /helidon + +ADD target/*.jar . +ADD target/libs libs +ADD runtimeCRaC.sh . +RUN chmod +x ./runtimeCRaC.sh + +ENTRYPOINT ["./runtimeCRaC.sh"] + +EXPOSE 7001 + diff --git a/examples/crac/Dockerfile.native_image b/examples/crac/Dockerfile.native_image new file mode 100644 index 00000000000..fb147df90a4 --- /dev/null +++ b/examples/crac/Dockerfile.native_image @@ -0,0 +1,17 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# TODO: native image for comparison \ No newline at end of file diff --git a/examples/crac/README.md b/examples/crac/README.md new file mode 100644 index 00000000000..af5f73e66af --- /dev/null +++ b/examples/crac/README.md @@ -0,0 +1,41 @@ +# Helidon MP on CRaC +[Coordinated Restore at Checkpoint](https://wiki.openjdk.org/display/crac) + + +## Runtime CRaC +Standard docker build doesn't support privileged access to the host machine kernel, +therefore CRaC checkpoint needs to be created in runtime. + +```bash +mvn clean package +docker build --build-arg CR_DIR=~/cr -t crac-helloworld . -f Dockerfile.crac +# First time ran, checkpoint is created, stop with Ctrl-C +docker run --privileged -p 7001:7001 --name crac-helloworld crac-helloworld +# Second time starting from checkpoint, stop with Ctrl-C +docker start -i crac-helloworld +``` + +### Exercise the app +``` +curl -X GET http://localhost:7001/helloworld +curl -X GET http://localhost:7001/helloworld/earth +curl -X GET http://localhost:7001/another +``` + +## Kubernetes CRaC + +```shell +minikube start +bash deploy-minikube.sh +curl $(minikube service crac-helloworld -n crac-helloworld --url)/helloworld/earth | jq +``` + +```shell +kubectl get pods +# Check first start - leghtly checkpoint creation +kubectl logs --previous --tail=100 -l app=crac-helloworld +# Check restart - fast checkpoint restoration +kubectl logs -l app=crac-helloworld +# Scale-up quickly +kubectl scale --replicas=3 deployment/crac-helloworld +``` \ No newline at end of file diff --git a/examples/crac/app.yaml b/examples/crac/app.yaml new file mode 100644 index 00000000000..1f9248324ff --- /dev/null +++ b/examples/crac/app.yaml @@ -0,0 +1,64 @@ +kind: Service +apiVersion: v1 +metadata: + name: crac-helloworld + labels: + app: crac-helloworld +spec: + type: NodePort + selector: + app: crac-helloworld + ports: + - port: 7001 + targetPort: 7001 + name: http +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: crac-checkpoint +spec: + accessModes: + - ReadWriteOnce + capacity: + storage: 1Gi + hostPath: + path: /data/crac-checkpoint/ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: crac-helloworld + labels: + app: crac-helloworld +spec: + replicas: 1 + selector: + matchLabels: + app: crac-helloworld + template: + metadata: + labels: + app: crac-helloworld + spec: + containers: + - name: crac-helloworld + image: crac-helloworld + imagePullPolicy: IfNotPresent + volumeMounts: + - mountPath: /crac-checkpoint + name: crac-checkpoint + ports: + - containerPort: 7001 + securityContext: + # TODO: be nicer + privileged: true + readinessProbe: + tcpSocket: + port: 7001 + initialDelaySeconds: 1 + periodSeconds: 1 + volumes: + - name: crac-checkpoint + hostPath: + path: /crac-checkpoint \ No newline at end of file diff --git a/examples/crac/deploy-minikube.sh b/examples/crac/deploy-minikube.sh new file mode 100644 index 00000000000..78b3fc558c8 --- /dev/null +++ b/examples/crac/deploy-minikube.sh @@ -0,0 +1,28 @@ +#!/bin/bash -e +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +eval $(minikube docker-env) +NAMESPACE=crac-helloworld + +mvn package -DskipTests +docker build -t crac-helloworld . -f Dockerfile.crac + +kubectl delete namespace ${NAMESPACE} +# Cleanup any previous checkpoint +minikube ssh "sudo rm -rf /crac-checkpoint/cr" +kubectl create namespace ${NAMESPACE} +kubectl config set-context --current --namespace=${NAMESPACE} +kubectl apply -f . --namespace ${NAMESPACE} \ No newline at end of file diff --git a/examples/crac/pom.xml b/examples/crac/pom.xml new file mode 100644 index 00000000000..6023fd346ed --- /dev/null +++ b/examples/crac/pom.xml @@ -0,0 +1,88 @@ + + + + + 4.0.0 + + io.helidon.applications + helidon-mp + 3.0.3-SNAPSHOT + ../../../applications/mp/pom.xml + + io.helidon.examples.microprofile + helidon-examples-microprofile-hello-world-implicit + Helidon Microprofile Examples Implicit Hello World + + + Microprofile example with implicit bootstrapping (cdi.Main(new String[0]) + + + + + io.helidon.microprofile.bundles + helidon-microprofile + + + org.jboss + jandex + runtime + true + + + io.helidon.microprofile.tests + helidon-microprofile-tests-junit5 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + org.jboss.jandex + jandex-maven-plugin + + + make-index + + + + + + diff --git a/examples/crac/runtimeCRaC.sh b/examples/crac/runtimeCRaC.sh new file mode 100644 index 00000000000..a45b01968c2 --- /dev/null +++ b/examples/crac/runtimeCRaC.sh @@ -0,0 +1,45 @@ +#!/bin/bash -e + +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if [ ! -d "$CR_DIR" ]; +then + echo "==== Creating CRaC checkpoint ====" + echo "=== Checking CRIU compatibility(don't forget --privileged) ===" + $JAVA_HOME/lib/criu check + + echo "=== Checking glibc version ===" + # glibc version higher than 2.34.9000-29 are known to have problems with rseq + # on some kernels, workaround GLIBC_TUNABLES=glibc.pthread.rseq=0 + ldd --version | grep ldd + # Workaround for https://github.com/checkpoint-restore/criu/issues/1696 + # see https://github.com/checkpoint-restore/criu/pull/1706 + export GLIBC_TUNABLES=glibc.pthread.rseq=0 + + echo "=== Pre-starting Helidon MP app ===" + set +e + $JAVA_HOME/bin/java -XX:CRaCCheckpointTo=/crac-checkpoint/cr -jar ./*.jar + set -e + + echo "=== CRaC checkpoint created, checking log dump for errors ===" + cat $CR_DIR/dump*.log | grep "Warn\|Err\|succ" +else +echo "==== Starting directly from CRaC checkpoint ====" +exec $JAVA_HOME/bin/java -XX:CRaCRestoreFrom=$CR_DIR +fi + + diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java new file mode 100644 index 00000000000..8807e0e00a4 --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018,2020 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +/** + * Resource showing all possible configuration injections. + */ +@Path("another") +@RequestScoped +public class AnotherResource { + @Inject + @ConfigProperty(name = "app.nonExistent", defaultValue = "145") + private int defaultValue; + + @Inject + @ConfigProperty(name = "app.nonExistent") + private Optional empty; + + @Inject + @ConfigProperty(name = "app.uri") + private Optional full; + + @Inject + @ConfigProperty(name = "app.someInt") + private Provider provider; + + @Inject + @ConfigProperty(name = "app.ints") + private List ints; + + @Inject + @ConfigProperty(name = "app.ints") + private Optional> optionalInts; + + @Inject + @ConfigProperty(name = "app.ints") + private Provider> providedInts; + + @Inject + @ConfigProperty(name = "app.ints") + private int[] intsArray; + + @Inject + @ConfigProperty(name = "app") + private Map detached; + + @Inject + private Config mpConfig; + + @Inject + private io.helidon.config.Config helidonConfig; + + /** + * Get method to validate that all injections worked. + * + * @return data from all fields of this class + */ + @GET + public String get() { + return toString(); + } + + @Override + public String toString() { + return "AnotherResource{" + + "defaultValue=" + defaultValue + + ", empty=" + empty + + ", full=" + full + + ", provider=" + provider + "(" + provider.get() + ")" + + ", ints=" + ints + + ", optionalInts=" + optionalInts + + ", providedInts=" + providedInts + "(" + providedInts.get() + ")" + + ", detached=" + detached + + ", microprofileConfig=" + mpConfig + + ", helidonConfig=" + helidonConfig + + ", intsArray=" + Arrays.toString(intsArray) + + '}'; + } +} diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java new file mode 100644 index 00000000000..4fe49e4ca08 --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit; + +import java.net.URI; +import java.util.Collections; +import java.util.logging.Logger; + +import io.helidon.config.Config; +import io.helidon.microprofile.example.helloworld.implicit.cdi.LoggerQualifier; +import io.helidon.microprofile.example.helloworld.implicit.cdi.RequestId; +import io.helidon.microprofile.example.helloworld.implicit.cdi.ResourceProducer; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.inject.spi.BeanManager; +import jakarta.inject.Inject; +import jakarta.json.Json; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonObject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +/** + * Resource for hello world example. + */ +@Path("helloworld") +@RequestScoped +public class HelloWorldResource { + + private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); + + private final Config config; + private final Logger logger; + private final int requestId; + private final String applicationName; + private final URI applicationUri; + private BeanManager beanManager; + + /** + * Using constructor injection for field values. + * + * @param config configuration instance + * @param logger logger (from {@link ResourceProducer} + * @param requestId requestId (from {@link ResourceProducer} + * @param appName name from configuration (app.name) + * @param appUri URI from configuration (app.uri) + * @param beanManager bean manager (injected automatically by CDI) + */ + @Inject + public HelloWorldResource(Config config, + @LoggerQualifier Logger logger, + @RequestId int requestId, + @ConfigProperty(name = "app.name") String appName, + @ConfigProperty(name = "app.uri") URI appUri, + BeanManager beanManager) { + this.config = config; + this.logger = logger; + this.requestId = requestId; + this.applicationName = appName; + this.applicationUri = appUri; + this.beanManager = beanManager; + } + + /** + * Get method for this resource, shows logger and request id. + * + * @return hello world + */ + @GET + @Produces(MediaType.TEXT_PLAIN) + public String message() { + return "Hello World: " + logger + ", request: " + requestId + ", appName: " + applicationName; + } + + /** + * Get method for this resource, returning JSON. + * + * @param name name to add to response + * @return JSON structure with injected fields + */ + @Path("/{name}") + @GET + @Produces(MediaType.APPLICATION_JSON) + public JsonObject getHello(@PathParam("name") String name) { + return JSON.createObjectBuilder() + .add("name", name) + .add("requestId", requestId) + .add("appName", applicationName) + .add("appUri", String.valueOf(applicationUri)) + .add("config", config.get("server.port").asInt().get()) + .add("beanManager", beanManager.toString()) + .add("logger", logger.getName()) + .build(); + } +} diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java new file mode 100644 index 00000000000..7de3e86dbb7 --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit.cdi; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.inject.Qualifier; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Use this qualifier to inject logger instances. + */ +@Qualifier +@Retention(RUNTIME) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) +public @interface LoggerQualifier { +} diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java new file mode 100644 index 00000000000..c4e904e6c5e --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit.cdi; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import jakarta.inject.Qualifier; + +/** + * Request id qualifier to inject increasing request id. + */ +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) +public @interface RequestId { +} diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java new file mode 100644 index 00000000000..2eacb8ff66d --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit.cdi; + +import jakarta.enterprise.context.ApplicationScoped; + +/** + * Produce an ever increasing request id. + */ +@ApplicationScoped +public class RequestIdProducer { + +} diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java new file mode 100644 index 00000000000..206be30fb38 --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit.cdi; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.enterprise.inject.spi.InjectionPoint; + +/** + * Producer for various resources required by this example. + */ +@ApplicationScoped +public class ResourceProducer { + private static final AtomicInteger COUNTER = new AtomicInteger(); + + /** + * Each injection will increase the COUNTER. + * + * @return increased COUNTER value + */ + @Produces + @RequestId + public int produceRequestId() { + return COUNTER.incrementAndGet(); + } + + /** + * Create/get a logger instance for the class that the logger is being injected into. + * + * @param injectionPoint injection point + * @return a logger instance + */ + @Produces + @LoggerQualifier + public java.util.logging.Logger produceLogger(final InjectionPoint injectionPoint) { + return java.util.logging.Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); + } +} diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java new file mode 100644 index 00000000000..3de41659971 --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * CDI classes for example. + */ +package io.helidon.microprofile.example.helloworld.implicit.cdi; diff --git a/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java new file mode 100644 index 00000000000..6c8d109a135 --- /dev/null +++ b/examples/crac/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Implicit HelloWorld example (starts server without configuration). + */ +package io.helidon.microprofile.example.helloworld.implicit; diff --git a/examples/crac/src/main/resources/META-INF/beans.xml b/examples/crac/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000000..1b3fbc297cb --- /dev/null +++ b/examples/crac/src/main/resources/META-INF/beans.xml @@ -0,0 +1,25 @@ + + + + diff --git a/examples/crac/src/main/resources/META-INF/microprofile-config.properties b/examples/crac/src/main/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..55832bf20f6 --- /dev/null +++ b/examples/crac/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1,27 @@ +# +# Copyright (c) 2020 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +app.name=Hello World Application +app.someInt=147 +app.uri=https://www.example.com +app.someInt=147 +app.ints=12,12,32,12,44 + +server.host=0.0.0.0 +server.port=7001 + +# Enable the optional MicroProfile Metrics REST.request metrics +metrics.rest-request.enabled=true diff --git a/examples/crac/src/main/resources/logging.properties b/examples/crac/src/main/resources/logging.properties new file mode 100644 index 00000000000..2f4a11a6f0c --- /dev/null +++ b/examples/crac/src/main/resources/logging.properties @@ -0,0 +1,20 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +handlers=io.helidon.common.HelidonConsoleHandler +java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n +.level=INFO +io.helidon.microprofile.config.level=FINEST diff --git a/examples/crac/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java b/examples/crac/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java new file mode 100644 index 00000000000..2e5e7e3b072 --- /dev/null +++ b/examples/crac/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.example.helloworld.implicit; + +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import jakarta.inject.Inject; +import jakarta.json.JsonObject; +import jakarta.ws.rs.client.WebTarget; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertAll; + +/** + * Unit test for {@link HelloWorldResource}. + */ +@HelidonTest +@Disabled("3.0.0-JAKARTA") // OpenAPI: Caused by: java.lang.NoSuchMethodError: + // 'java.util.List org.jboss.jandex.ClassInfo.unsortedFields()' +class ImplicitHelloWorldTest { + private final WebTarget target; + + @Inject + ImplicitHelloWorldTest(WebTarget target) { + this.target = target; + } + @Test + void testJsonResource() { + JsonObject jsonObject = target + .path("/helloworld/unit") + .request() + .get(JsonObject.class); + + assertAll("JSON fields must match expected injection values", + () -> assertThat("Name from request", jsonObject.getString("name"), is("unit")), + () -> assertThat("Request id from CDI provider", jsonObject.getInt("requestId"), is(1)), + () -> assertThat("App name from config", jsonObject.getString("appName"), is("Hello World Application")), + () -> assertThat("Logger name", jsonObject.getString("logger"), is(HelloWorldResource.class.getName())) + ); + + } +} diff --git a/microprofile/server/pom.xml b/microprofile/server/pom.xml index 5724895cb05..fd7a2fa0424 100644 --- a/microprofile/server/pom.xml +++ b/microprofile/server/pom.xml @@ -51,6 +51,10 @@ io.helidon.webserver.observe helidon-webserver-observe + + io.github.crac + org-crac + io.helidon.microprofile.cdi helidon-microprofile-cdi diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java index 1866eb47d09..cf5e279c92f 100644 --- a/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java +++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java @@ -24,11 +24,15 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -79,6 +83,10 @@ import jakarta.enterprise.inject.spi.ProcessProducerMethod; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.ext.ParamConverterProvider; +import org.crac.CheckpointException; +import org.crac.Core; +import org.crac.Resource; +import org.crac.RestoreException; import org.eclipse.microprofile.config.ConfigProvider; import org.glassfish.jersey.internal.inject.Bindings; import org.glassfish.jersey.internal.inject.InjectionManager; @@ -92,7 +100,7 @@ /** * Extension to handle web server configuration and lifecycle. */ -public class ServerCdiExtension implements Extension { +public class ServerCdiExtension implements Extension, Resource { private static final System.Logger LOGGER = System.getLogger(ServerCdiExtension.class.getName()); private static final System.Logger STARTUP_LOGGER = System.getLogger("io.helidon.microprofile.startup.server"); private static final AtomicBoolean IN_PROGRESS_OR_RUNNING = new AtomicBoolean(); @@ -120,10 +128,16 @@ public class ServerCdiExtension implements Extension { private Context context; + private final Set routingsWithKPIMetrics = new HashSet<>(); + private long cracRestoreTime = -1; + private final CompletableFuture> restored = new CompletableFuture<>(); + + /** * Default constructor required by {@link java.util.ServiceLoader}. */ public ServerCdiExtension() { + Core.getGlobalContext().register(this); } /** @@ -459,6 +473,16 @@ private void startServer(@Observes @Priority(PLATFORM_AFTER + 100) @Initialized( } webserver = serverBuilder.build(); + try { + Core.checkpointRestore(); + } catch (UnsupportedOperationException e) { + LOGGER.log(java.util.logging.Level.FINEST, "CRaC feature is not available", e); + } catch (RestoreException e) { + LOGGER.log(java.util.logging.Level.SEVERE, "CRaC restore wasn't successful!", e); + } catch (CheckpointException e) { + LOGGER.log(java.util.logging.Level.SEVERE, "CRaC checkpoint creation wasn't successful!", e); + } + try { webserver.start(); started = true; @@ -474,9 +498,14 @@ private void startServer(@Observes @Priority(PLATFORM_AFTER + 100) @Initialized( String host = "0.0.0.0".equals(listenHost) ? "localhost" : listenHost; String note = "0.0.0.0".equals(listenHost) ? " (and all other host addresses)" : ""; + + String startupTimeReport = cracRestoreTime == -1 + ? " in " + initializationElapsedTime + " milliseconds (since JVM startup). " + : " in " + (System.currentTimeMillis() - cracRestoreTime) + " milliseconds (since CRaC restore)."; + LOGGER.log(Level.INFO, () -> "Server started on " + protocol + "://" + host + ":" + port - + note + " in " + initializationElapsedTime + " milliseconds (since JVM startup)."); + + note + startupTimeReport); // this is not needed at runtime, collect garbage serverBuilder = null; @@ -731,4 +760,17 @@ private HttpRouting.Builder findRouting(String className, return serverNamedRoutingBuilder(routingName); } + + @Override + public void beforeCheckpoint(org.crac.Context context) throws Exception { + LOGGER.log(Level.INFO, "Creating CRaC snapshot after " + + ManagementFactory.getRuntimeMXBean().getUptime() + + "ms of runtime."); + } + + @Override + public void afterRestore(org.crac.Context context) throws Exception { + cracRestoreTime = System.currentTimeMillis(); + LOGGER.log(java.util.logging.Level.INFO, "CRaC snapshot restored!"); + } } diff --git a/microprofile/server/src/main/java/module-info.java b/microprofile/server/src/main/java/module-info.java index 20fe3655a7f..09060d8124b 100644 --- a/microprofile/server/src/main/java/module-info.java +++ b/microprofile/server/src/main/java/module-info.java @@ -37,6 +37,7 @@ requires static io.helidon.common.features.api; requires static io.helidon.config.metadata; + requires org.crac; requires transitive io.helidon.common.configurable; requires transitive io.helidon.common.context; From 5444bf216e36b7cc16984c572d4c4ea0697fd37d Mon Sep 17 00:00:00 2001 From: Daniel Kec Date: Fri, 10 May 2024 13:04:28 +0200 Subject: [PATCH 2/7] Upgrade to H4 with Liberica Signed-off-by: Daniel Kec --- examples/crac/Dockerfile.crac | 19 ++++++++--------- examples/crac/Dockerfile.native_image | 17 --------------- examples/crac/pom.xml | 21 ++++++++++++------- examples/crac/runtimeCRaC.sh | 1 + .../helloworld/implicit/AnotherResource.java | 2 +- .../helloworld/implicit/package-info.java | 2 +- .../META-INF/microprofile-config.properties | 1 - .../src/main/resources/logging.properties | 4 ++-- .../implicit/ImplicitHelloWorldTest.java | 7 ++----- .../server/ServerCdiExtension.java | 12 ++++------- 10 files changed, 33 insertions(+), 53 deletions(-) delete mode 100644 examples/crac/Dockerfile.native_image diff --git a/examples/crac/Dockerfile.crac b/examples/crac/Dockerfile.crac index e239f63fb32..0776d01fc6b 100644 --- a/examples/crac/Dockerfile.crac +++ b/examples/crac/Dockerfile.crac @@ -13,31 +13,30 @@ # See the License for the specific language governing permissions and # limitations under the License. # -FROM debian:stretch-slim as ubuntu-crac +FROM container-registry.oracle.com/os/oraclelinux:9-slim as olinux-crac WORKDIR /usr/share ARG CHECKPOINT_DIR -ENV CRAC_ARTEFACT=openjdk-17-crac+3_linux-x64 -ENV JAVA_HOME=/usr/share/$CRAC_ARTEFACT +ENV JDK_NAME=jdk-21.0.3-crac +ENV JAVA_HOME=/usr/share/$JDK_NAME ENV CR_DIR=${CONT_IMG_VER:-/crac-checkpoint/cr} # Install CRaC -RUN apt-get -qq update && apt-get install -y wget -RUN wget https://github.com/CRaC/openjdk-builds/releases/download/17-crac%2B3/$CRAC_ARTEFACT.tar.gz \ -&& tar zxf $CRAC_ARTEFACT.tar.gz \ -&& ln -s $JAVA_HOME/bin/java /bin/ +RUN microdnf -y update && microdnf -y install wget tar gzip +RUN wget -O crac-jdk.tar.gz "https://download.bell-sw.com/java/21.0.3+11/bellsoft-jdk21.0.3+11-linux-amd64-crac.tar.gz" +RUN tar zxf ./crac-jdk.tar.gz -C /usr/share && ln -s $JAVA_HOME/bin/java /bin/ -FROM ubuntu-crac +FROM olinux-crac WORKDIR /helidon ADD target/*.jar . ADD target/libs libs ADD runtimeCRaC.sh . -RUN chmod +x ./runtimeCRaC.sh +RUN chmod +x ./runtimeCRaC.sh && ls -la /helidon -ENTRYPOINT ["./runtimeCRaC.sh"] +CMD ["sh","./runtimeCRaC.sh"] EXPOSE 7001 diff --git a/examples/crac/Dockerfile.native_image b/examples/crac/Dockerfile.native_image deleted file mode 100644 index fb147df90a4..00000000000 --- a/examples/crac/Dockerfile.native_image +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# TODO: native image for comparison \ No newline at end of file diff --git a/examples/crac/pom.xml b/examples/crac/pom.xml index 6023fd346ed..60b20c36620 100644 --- a/examples/crac/pom.xml +++ b/examples/crac/pom.xml @@ -1,7 +1,7 @@