diff --git a/.github/workflows/graalvm-native-test.yml b/.github/workflows/graalvm-native-test.yml new file mode 100644 index 0000000000..6529cdfb0b --- /dev/null +++ b/.github/workflows/graalvm-native-test.yml @@ -0,0 +1,45 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +name: NativeTest by GraalVM CE with Maven + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + strategy: + matrix: + java: [ '21' ] + os: [ 'ubuntu-latest' ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Set up GraalVM CE ${{ matrix.java }} + uses: graalvm/setup-graalvm@v1 + with: + java-version: ${{ matrix.java }} + distribution: 'graalvm-community' + github-token: ${{ secrets.GITHUB_TOKEN }} + cache: 'maven' + - name: Build NativeTest with Maven + continue-on-error: true + run: | + ./mvnw -PnativeTestInElasticJob -T1C -B -e clean test diff --git a/docs/content/user-manual/elasticjob-lite/configuration/graalvm-native-image.cn.md b/docs/content/user-manual/elasticjob-lite/configuration/graalvm-native-image.cn.md new file mode 100644 index 0000000000..5a76124f4a --- /dev/null +++ b/docs/content/user-manual/elasticjob-lite/configuration/graalvm-native-image.cn.md @@ -0,0 +1,82 @@ ++++ +title = "GraalVM Native Image 支持" +weight = 6 +chapter = true ++++ + +## 对 GraalVM Native Image 的支持 + +ElasticJob Lite 提供了构建 GraalVM Native Image 所需要的 GraalVM Reachability Metadata。在 `pom.xml` 引入 `elasticjob-lite-core` 后无需额外处理。 + +```xml + + + + org.apache.shardingsphere.elasticjob + elasticjob-lite-core + ${project.version} + + + +``` + +## 内部的 GraalVM Reachability Metadata 条目 + +`org.apache.shardingsphere.elasticjob:elasticjob-infra-reachability-metadata` 托管了如下 Maven 库的 GraalVM Reachability +Metadata,一旦 https://github.com/oracle/graalvm-reachability-metadata 对如下库的 GraalVM Reachability Metadata 进行了 +Release 流程, 下列第三方库的相关 JSON 文件将在 ElasticJob 一侧被删除。 + +- `org.apache.zookeeper:zookeeper:3.9.0` +- `org.apache.curator:curator-client:5.5.0` +- `org.apache.curator:curator-framework:5.5.0` +- `org.apache.curator:curator-recipes:5.5.0` +- `org.apache.shardingsphere.elasticjob:elasticjob-lite-core:${project.version}` + +用户可以通过在自有项目的资源根目录或测试资源文件夹,通过新建对应库信息的 `/META-INF/native-image/${project.groupId}/${project.artifactId}/${project.version}` +文件夹来覆写被传入项目的 GraalVM Reachability Metadata 。 + +用户依然可以自己编写 GraalVM Reachability Metadata 的相关文件来为缺少 GraalVM Reachability Metadata 的类库提供 GraalVM Native Image 支持。 + +## 已知限制 + +1. 用户无法在 GraalVM Native Image 使用 elasticJobType 为 SCRIPT 的 Job。参考 https://github.com/oracle/graal/issues/7390 。 + +2. 用户无法在 GraalVM Native Image 下使用与 `org.apache.shardingsphere.elasticjob.tracing.api.TracingConfiguration` 相关的 Tracing 功能。 + +3. ElasticJob 的 Spring Boot Starter 尚未在 GraalVM Native Image 下可用。 + +## 贡献 GraalVM Reachability Metadata + +此节文本针对贡献者。假设贡献者位于新的 Ubuntu 22.04.3 实例下,可通过 `SDKMAN!` 初始化 `GraalVM CE` 环境。 + +```bash +sdk install java 21-graalce +sdk use java 21-graalce +sudo apt-get install build-essential libz-dev zlib1g-dev -y +``` + +对于与 ElasticJob 无关的 GraalVM Reachability Metadata,相关的 issue 和 PR 应当首先创建在 https://github.com/oracle/graalvm-reachability-metadata 。 +该存储库使 GraalVM Native Image 的用户能够共享和重用 Java 生态系统中的库和框架的元数据。 + +ElasticJob 维护了一组单元测试子集,此子集避开对 Mockito 相关的 +类的使用,以服务于项目 CI 对 Native Image 的测试。参考 https://github.com/mockito/mockito/issues/2862 。 + +- `org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.**` + +在 ElasticJob 一侧,存在 Maven Profile 为 `generateMetadata`,用户可在 ElasticJob 项目根目录执行如下命令来采集 GraalVM Reachability Metadata。 +请手动删除无任何具体条目的 JSON 文件。 + +```bash +./mvnw -PgenerateMetadata -DskipNativeTests -e -T1C clean test native:metadata-copy +``` + +在 ElasticJob 一侧,存在 Maven Profile 为 `nativeTestInElasticJob`,用户可在 ElasticJob 项目根目录执行如下命令来执行特定于 GraalVM +Native Build Tools 的 nativeTest,以验证 GraalVM Native Image 中的单元测试覆盖率。 + +```bash +./mvnw -PnativeTestInElasticJob -T1C -e clean test +``` + +对于特定于单元测试的 GraalVM Reachability Metadata,请放置在 `${project.basedir}/src/test/resources/META-INF/native-image/${project.artifactId}-test-metadata/` +文件夹下,`${project.basedir}` 和 `${project.artifactId}` 为对应单元测试涉及的子模块。如有需要,请使用 `org.junit.jupiter.api.condition.DisabledInNativeImage` +注解或 `org.graalvm.nativeimage.imagecode` 的 System Property 屏蔽部分单元测试在 GraalVM Native Image 下运行。 diff --git a/docs/content/user-manual/elasticjob-lite/configuration/graalvm-native-image.en.md b/docs/content/user-manual/elasticjob-lite/configuration/graalvm-native-image.en.md new file mode 100644 index 0000000000..f4e9e6be93 --- /dev/null +++ b/docs/content/user-manual/elasticjob-lite/configuration/graalvm-native-image.en.md @@ -0,0 +1,92 @@ ++++ +title = "GraalVM Native Image Support" +weight = 6 +chapter = true ++++ + +## Support for GraalVM Native Image + +ElasticJob Lite provides the GraalVM Reachability Metadata needed to build GraalVM Native Images. No additional +processing is required after the introduction of `elasticjob-lite-core` in `pom.xml`. + +```xml + + + + org.apache.shardingsphere.elasticjob + elasticjob-lite-core + ${project.version} + + + +``` + +## Internal GraalVM Reachability Metadata entry + +`org.apache.shardingsphere.elasticjob:elasticjob-infra-reachability-metadata` hosts GraalVM Reachability Metadata for +the following Maven library, once https://github.com/oracle/graalvm-reachability-metadata is done Release process with +the GraalVM Reachability Metadata for the following libraries, the relevant JSON files for the following third-party +libraries will be deleted on the ElasticJob side. + +- `org.apache.zookeeper:zookeeper:3.9.0` +- `org.apache.curator:curator-client:5.5.0` +- `org.apache.curator:curator-framework:5.5.0` +- `org.apache.curator:curator-recipes:5.5.0` +- `org.apache.shardingsphere.elasticjob:elasticjob-lite-core:${project.version}` + +Users can create a new corresponding library folder called `/META-INF/native-image/${project.groupId}/${project.artifactId}/${project.version}` +in the resource root directory of their own project or test resource folder to override the GraalVM Reachability +Metadata of the incoming project. + +Users can still write their own GraalVM Reachability Metadata files to provide GraalVM Native Image support for +libraries that lack GraalVM Reachability Metadata. + +## Known limitations + +1. Users cannot use jobs with `elasticJobType` as `SCRIPT` in GraalVM Native Image. Refer to https://github.com/oracle/graal/issues/7390 . + +2. Users cannot use the tracing function related to `org.apache.shardingsphere.elasticjob.tracing.api.TracingConfiguration` +under GraalVM Native Image. + +3. ElasticJob's Spring Boot Starter is not yet available under GraalVM Native Image. + +## Contribute GraalVM Reachability Metadata + +This section text is for contributors. Assuming the contributor is under a new Ubuntu 22.04.3 instance, the `GraalVM CE` +environment can be initialized via `SDKMAN!`. + +```bash +sdk install java 21-graalce +sdk use java 21-graalce +sudo apt-get install build-essential libz-dev zlib1g-dev -y +``` + +For GraalVM Reachability Metadata that is not related to ElasticJob, issues and PRs should first be created in the https://github.com/oracle/graalvm-reachability-metadata . +The repository enables users of GraalVM Native Image to share and reuse metadata for libraries and frameworks in the +Java ecosystem. + +ElasticJob maintains a subset of unit tests that eschews the use of Mockito-related classes to serve the project CI's +testing of Native Images. Refer to https://github.com/mockito/mockito/issues/2862 . + +- `org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.**` + +On the ElasticJob side, there is a Maven Profile as `generateMetadata`, and users can execute the following command in +the root directory of the ElasticJob project to capture GraalVM Reachability Metadata. Manually delete the JSON file +without any specific entries. + +```bash +./mvnw -PgenerateMetadata -DskipNativeTests -e -T1C clean test native:metadata-copy +``` + +On the ElasticJob side, there is a Maven Profile as `nativeTestInElasticJob`, and users can execute the following +command at the root of the ElasticJob project to execute GraalVM-specific nativeTest of Native Build Tools to verify +unit test coverage in GraalVM Native Image. + +```bash +./mvnw -PnativeTestInElasticJob -T1C -e clean test +``` + +For GraalVM Reachability Metadata specific to unit tests, be placed in `${project.basedir}/src/test/resources/META-INF/native-image/${project.artifactId}-test-metadata/` +folder, `${project.basedir}` and `${project.artifactId}` are submodules involved in the corresponding unit test. If +needed, use `org.junit.jupiter.api.condition.DisabledInNativeImage` annotations or `org.graalvm.nativeimage.imagecode` +System Property masked unit tests to run under GraalVM Native Image. diff --git a/elasticjob-ecosystem/elasticjob-error-handler/elasticjob-error-handler-type/elasticjob-error-handler-general/pom.xml b/elasticjob-ecosystem/elasticjob-error-handler/elasticjob-error-handler-type/elasticjob-error-handler-general/pom.xml index 9184609e4a..a3619c866b 100644 --- a/elasticjob-ecosystem/elasticjob-error-handler/elasticjob-error-handler-type/elasticjob-error-handler-general/pom.xml +++ b/elasticjob-ecosystem/elasticjob-error-handler/elasticjob-error-handler-type/elasticjob-error-handler-general/pom.xml @@ -46,7 +46,12 @@ org.projectlombok lombok - + + + ch.qos.logback + logback-core + test + ch.qos.logback logback-classic diff --git a/elasticjob-infra/elasticjob-infra-reachability-metadata/pom.xml b/elasticjob-infra/elasticjob-infra-reachability-metadata/pom.xml new file mode 100644 index 0000000000..f231cf4305 --- /dev/null +++ b/elasticjob-infra/elasticjob-infra-reachability-metadata/pom.xml @@ -0,0 +1,30 @@ + + + + + 4.0.0 + + org.apache.shardingsphere.elasticjob + elasticjob-infra + 3.1.0-SNAPSHOT + + elasticjob-infra-reachability-metadata + ${project.artifactId} + diff --git a/elasticjob-infra/elasticjob-infra-reachability-metadata/src/main/resources/META-INF/native-image/org.apache.curator/curator-framework/5.5.0/reflect-config.json b/elasticjob-infra/elasticjob-infra-reachability-metadata/src/main/resources/META-INF/native-image/org.apache.curator/curator-framework/5.5.0/reflect-config.json new file mode 100644 index 0000000000..05dda55a71 --- /dev/null +++ b/elasticjob-infra/elasticjob-infra-reachability-metadata/src/main/resources/META-INF/native-image/org.apache.curator/curator-framework/5.5.0/reflect-config.json @@ -0,0 +1,12 @@ +[ +{ + "condition":{"typeReachable":"org.apache.curator.framework.imps.NamespaceFacadeCache"}, + "name":"org.apache.curator.shaded.com.google.common.util.concurrent.AbstractFuture", + "fields":[{"name":"listeners"}, {"name":"value"}, {"name":"waiters"}] +}, +{ + "condition":{"typeReachable":"org.apache.curator.framework.imps.NamespaceFacadeCache"}, + "name":"org.apache.curator.shaded.com.google.common.util.concurrent.AbstractFuture$Waiter", + "fields":[{"name":"next"}, {"name":"thread"}] +} +] diff --git a/elasticjob-infra/elasticjob-infra-reachability-metadata/src/main/resources/META-INF/native-image/org.apache.zookeeper/zookeeper/3.9.0/reflect-config.json b/elasticjob-infra/elasticjob-infra-reachability-metadata/src/main/resources/META-INF/native-image/org.apache.zookeeper/zookeeper/3.9.0/reflect-config.json new file mode 100644 index 0000000000..a6e52201ca --- /dev/null +++ b/elasticjob-infra/elasticjob-infra-reachability-metadata/src/main/resources/META-INF/native-image/org.apache.zookeeper/zookeeper/3.9.0/reflect-config.json @@ -0,0 +1,56 @@ +[ +{ + "condition":{"typeReachable":"org.apache.zookeeper.ZooKeeper"}, + "name":"org.apache.zookeeper.ClientCnxnSocketNIO", + "methods":[{"name":"","parameterTypes":["org.apache.zookeeper.client.ZKClientConfig"] }] +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.metrics.impl.MetricsProviderBootstrap"}, + "name":"org.apache.zookeeper.metrics.impl.DefaultMetricsProvider", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.quorum.QuorumPeerConfig"}, + "name":"org.apache.zookeeper.metrics.impl.DefaultMetricsProvider" +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ServerCnxnFactory"}, + "name":"org.apache.zookeeper.server.ConnectionBean", + "queryAllPublicConstructors":true +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ServerCnxnFactory"}, + "name":"org.apache.zookeeper.server.ConnectionMXBean", + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ZooKeeperServer"}, + "name":"org.apache.zookeeper.server.DataTreeBean", + "queryAllPublicConstructors":true +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ZooKeeperServer"}, + "name":"org.apache.zookeeper.server.DataTreeMXBean", + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ServerCnxnFactory"}, + "name":"org.apache.zookeeper.server.NIOServerCnxnFactory", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ZooKeeperServer"}, + "name":"org.apache.zookeeper.server.ZooKeeperServerBean", + "queryAllPublicConstructors":true +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.ZooKeeperServer"}, + "name":"org.apache.zookeeper.server.ZooKeeperServerMXBean", + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.apache.zookeeper.server.watch.WatchManagerFactory"}, + "name":"org.apache.zookeeper.server.watch.WatchManager", + "methods":[{"name":"","parameterTypes":[] }] +} +] diff --git a/elasticjob-infra/pom.xml b/elasticjob-infra/pom.xml index 0cc6395f77..ded3a6171b 100644 --- a/elasticjob-infra/pom.xml +++ b/elasticjob-infra/pom.xml @@ -31,5 +31,6 @@ elasticjob-infra-common elasticjob-registry-center elasticjob-restful + elasticjob-infra-reachability-metadata diff --git a/elasticjob-lite/elasticjob-lite-core/pom.xml b/elasticjob-lite/elasticjob-lite-core/pom.xml index 8de1f04b5f..f41720f04b 100644 --- a/elasticjob-lite/elasticjob-lite-core/pom.xml +++ b/elasticjob-lite/elasticjob-lite-core/pom.xml @@ -71,6 +71,11 @@ elasticjob-tracing-rdb ${project.parent.version} + + org.apache.shardingsphere.elasticjob + elasticjob-infra-reachability-metadata + ${project.version} + org.apache.commons @@ -119,4 +124,14 @@ test + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-maven-plugin.version} + + + diff --git a/elasticjob-lite/elasticjob-lite-core/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-lite-core/reflect-config.json b/elasticjob-lite/elasticjob-lite-core/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-lite-core/reflect-config.json new file mode 100644 index 0000000000..0f72d7a24a --- /dev/null +++ b/elasticjob-lite/elasticjob-lite-core/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-lite-core/reflect-config.json @@ -0,0 +1,80 @@ +[ +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.executor.ElasticJobExecutor"}, + "name":"java.util.Properties", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.failover.FailoverListenerManager"}, + "name":"java.util.Properties", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.reconcile.ReconcileService"}, + "name":"java.util.Properties", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.sharding.ShardingListenerManager$ListenServersChangedJobListener"}, + "name":"java.util.Properties", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.sharding.ShardingListenerManager$ShardingTotalCountChangedJobListener"}, + "name":"java.util.Properties", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.instance.InstanceNode"}, + "name":"org.apache.shardingsphere.elasticjob.infra.handler.sharding.JobInstance", + "allDeclaredFields":true, + "methods":[{"name":"getJobInstanceId","parameterTypes":[] }, {"name":"getLabels","parameterTypes":[] }, {"name":"getServerIp","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.executor.ElasticJobExecutor"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "methods":[{"name":"setCron","parameterTypes":["java.lang.String"] }, {"name":"setProps","parameterTypes":["java.util.Properties"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.infra.yaml.YamlEngine"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setDescription","parameterTypes":["java.lang.String"] }, {"name":"setDisabled","parameterTypes":["boolean"] }, {"name":"setFailover","parameterTypes":["boolean"] }, {"name":"setJobName","parameterTypes":["java.lang.String"] }, {"name":"setJobParameter","parameterTypes":["java.lang.String"] }, {"name":"setMaxTimeDiffSeconds","parameterTypes":["int"] }, {"name":"setMisfire","parameterTypes":["boolean"] }, {"name":"setMonitorExecution","parameterTypes":["boolean"] }, {"name":"setOverwrite","parameterTypes":["boolean"] }, {"name":"setReconcileIntervalMinutes","parameterTypes":["int"] }, {"name":"setShardingItemParameters","parameterTypes":["java.lang.String"] }, {"name":"setShardingTotalCount","parameterTypes":["int"] }, {"name":"setStaticSharding","parameterTypes":["boolean"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.ScheduleJobBootstrap"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "methods":[{"name":"setCron","parameterTypes":["java.lang.String"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.config.ConfigurationService"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "allDeclaredFields":true, + "methods":[{"name":"getCron","parameterTypes":[] }, {"name":"getDescription","parameterTypes":[] }, {"name":"getJobErrorHandlerType","parameterTypes":[] }, {"name":"getJobExecutorServiceHandlerType","parameterTypes":[] }, {"name":"getJobExtraConfigurations","parameterTypes":[] }, {"name":"getJobListenerTypes","parameterTypes":[] }, {"name":"getJobName","parameterTypes":[] }, {"name":"getJobParameter","parameterTypes":[] }, {"name":"getJobShardingStrategyType","parameterTypes":[] }, {"name":"getLabel","parameterTypes":[] }, {"name":"getMaxTimeDiffSeconds","parameterTypes":[] }, {"name":"getProps","parameterTypes":[] }, {"name":"getReconcileIntervalMinutes","parameterTypes":[] }, {"name":"getShardingItemParameters","parameterTypes":[] }, {"name":"getShardingTotalCount","parameterTypes":[] }, {"name":"getTimeZone","parameterTypes":[] }, {"name":"isDisabled","parameterTypes":[] }, {"name":"isFailover","parameterTypes":[] }, {"name":"isMisfire","parameterTypes":[] }, {"name":"isMonitorExecution","parameterTypes":[] }, {"name":"isOverwrite","parameterTypes":[] }, {"name":"isStaticSharding","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.failover.FailoverListenerManager"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "methods":[{"name":"setCron","parameterTypes":["java.lang.String"] }, {"name":"setProps","parameterTypes":["java.util.Properties"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.reconcile.ReconcileService"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "methods":[{"name":"setCron","parameterTypes":["java.lang.String"] }, {"name":"setProps","parameterTypes":["java.util.Properties"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.sharding.ShardingListenerManager$ListenServersChangedJobListener"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "methods":[{"name":"setCron","parameterTypes":["java.lang.String"] }, {"name":"setProps","parameterTypes":["java.util.Properties"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.sharding.ShardingListenerManager$ShardingTotalCountChangedJobListener"}, + "name":"org.apache.shardingsphere.elasticjob.infra.pojo.JobConfigurationPOJO", + "methods":[{"name":"setCron","parameterTypes":["java.lang.String"] }, {"name":"setProps","parameterTypes":["java.util.Properties"] }] +}, +{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobScheduler"}, + "name":"org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobShutdownHookPlugin", + "methods":[{"name":"","parameterTypes":[] }, {"name":"setCleanShutdown","parameterTypes":["boolean"] }] +} +] diff --git a/elasticjob-lite/elasticjob-lite-core/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-lite-core/resource-config.json b/elasticjob-lite/elasticjob-lite-core/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-lite-core/resource-config.json new file mode 100644 index 0000000000..cba6a606ab --- /dev/null +++ b/elasticjob-lite/elasticjob-lite-core/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-lite-core/resource-config.json @@ -0,0 +1,29 @@ +{ + "resources":{ + "includes":[{ + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobScheduler"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.error.handler.JobErrorHandlerPropertiesValidator\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.error.handler.JobErrorHandlerFactory"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.error.handler.JobErrorHandler\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.executor.item.JobItemExecutorFactory"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.executor.item.impl.ClassedJobItemExecutor\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.executor.item.JobItemExecutorFactory"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.executor.item.impl.TypedJobItemExecutor\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.executor.context.ExecutorContext"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.infra.context.Reloadable\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.infra.handler.threadpool.JobExecutorServiceHandlerFactory"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.infra.handler.threadpool.JobExecutorServiceHandler\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.lite.internal.setup.JobClassNameProviderFactory"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.lite.internal.setup.JobClassNameProvider\\E" + }, { + "condition":{"typeReachable":"org.apache.shardingsphere.elasticjob.reg.exception.RegExceptionHandler"}, + "pattern":"\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.reg.exception.IgnoredExceptionProvider\\E" + }]}, + "bundles":[] +} diff --git a/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/ElasticjobLiteCoreTest.java b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/ElasticjobLiteCoreTest.java new file mode 100644 index 0000000000..c020a5874c --- /dev/null +++ b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/ElasticjobLiteCoreTest.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata; + +import org.apache.curator.CuratorZookeeperClient; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.curator.test.TestingServer; +import org.apache.shardingsphere.elasticjob.api.JobConfiguration; +import org.apache.shardingsphere.elasticjob.api.ShardingContext; +import org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob; +import org.apache.shardingsphere.elasticjob.dataflow.props.DataflowJobProperties; +import org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties; +import org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.OneOffJobBootstrap; +import org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.ScheduleJobBootstrap; +import org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.entity.TOrderPOJO; +import org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.repository.VirtualTOrderRepository; +import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter; +import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration; +import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter; +import org.apache.shardingsphere.elasticjob.simple.job.SimpleJob; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.time.Duration; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ElasticjobLiteCoreTest { + private static final int PORT = 6891; + + private static final VirtualTOrderRepository VIRTUAL_T_ORDER_REPOSITORY = new VirtualTOrderRepository(); + + private static volatile TestingServer testingServer; + + private static CoordinatorRegistryCenter registryCenter; + + @BeforeAll + static void beforeAll() throws Exception { + testingServer = new TestingServer(PORT, true); + try (CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(), + 60 * 1000, 500, null, + new ExponentialBackoffRetry(500, 3, 500 * 3))) { + client.start(); + Awaitility.await() + .atMost(Duration.ofMillis(500 * 60)) + .untilAsserted(() -> assertTrue(client.isConnected())); + // CHECKSTYLE:OFF + } catch (Exception e) { + // CHECKSTYLE:ON + throw new RuntimeException(e); + } + registryCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(testingServer.getConnectString(), "elasticjob-lite-core-java-test")); + registryCenter.init(); + } + + @AfterAll + static void afterAll() throws IOException { + registryCenter.close(); + testingServer.close(); + } + + @Test + void testJavaHttpJob() { + ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(registryCenter, "HTTP", + JobConfiguration.newBuilder("testJavaHttpJob", 3) + .setProperty(HttpJobProperties.URI_KEY, "https://google.com") + .setProperty(HttpJobProperties.METHOD_KEY, "GET") + .cron("0/5 * * * * ?") + .shardingItemParameters("0=Norddorf,1=Bordeaux,2=Somerset") + .build() + ); + assertDoesNotThrow(() -> { + jobBootstrap.schedule(); + jobBootstrap.shutdown(); + }); + } + + @Test + void testJavaSimpleJob() { + ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(registryCenter, + (SimpleJob) shardingContext -> { + assertThat(shardingContext.getShardingItem(), is(3)); + VIRTUAL_T_ORDER_REPOSITORY.findTodoData(shardingContext.getShardingParameter(), 10) + .forEach(each -> VIRTUAL_T_ORDER_REPOSITORY.setCompleted(each.getId())); + }, + JobConfiguration.newBuilder("testJavaSimpleJob", 3) + .cron("0/5 * * * * ?") + .shardingItemParameters("0=Norddorf,1=Bordeaux,2=Somerset") + .build() + ); + assertDoesNotThrow(() -> { + jobBootstrap.schedule(); + jobBootstrap.shutdown(); + }); + } + + @Test + void testJavaDataflowElasticJob() { + ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(registryCenter, new DataflowJob() { + @Override + public List fetchData(final ShardingContext shardingContext) { + assertThat(shardingContext.getShardingItem(), is(3)); + return VIRTUAL_T_ORDER_REPOSITORY.findTodoData(shardingContext.getShardingParameter(), 10); + } + + @Override + public void processData(final ShardingContext shardingContext, final List data) { + assertThat(shardingContext.getShardingItem(), is(3)); + data.stream().mapToLong(TOrderPOJO::getId).forEach(VIRTUAL_T_ORDER_REPOSITORY::setCompleted); + } + }, + JobConfiguration.newBuilder("testJavaDataflowElasticJob", 3) + .cron("0/5 * * * * ?") + .shardingItemParameters("0=Norddorf,1=Bordeaux,2=Somerset") + .setProperty(DataflowJobProperties.STREAM_PROCESS_KEY, Boolean.TRUE.toString()) + .build() + ); + assertDoesNotThrow(() -> { + jobBootstrap.schedule(); + jobBootstrap.shutdown(); + }); + } + + @Test + void testJavaOneOffSimpleJob() { + OneOffJobBootstrap jobBootstrap = new OneOffJobBootstrap(registryCenter, + (SimpleJob) shardingContext -> { + assertThat(shardingContext.getShardingItem(), is(3)); + VIRTUAL_T_ORDER_REPOSITORY.findTodoData(shardingContext.getShardingParameter(), 10) + .forEach(each -> VIRTUAL_T_ORDER_REPOSITORY.setCompleted(each.getId())); + }, + JobConfiguration.newBuilder("testJavaOneOffSimpleJob", 3) + .shardingItemParameters("0=Norddorf,1=Bordeaux,2=Somerset") + .build() + ); + assertDoesNotThrow(() -> { + jobBootstrap.execute(); + jobBootstrap.shutdown(); + }); + } +} diff --git a/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/entity/TOrderPOJO.java b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/entity/TOrderPOJO.java new file mode 100644 index 0000000000..3cfceafec4 --- /dev/null +++ b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/entity/TOrderPOJO.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +public final class TOrderPOJO implements Serializable { + private long id; + + private String location; + + private TableStatus tableStatus; +} diff --git a/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/entity/TableStatus.java b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/entity/TableStatus.java new file mode 100644 index 0000000000..d53e241b13 --- /dev/null +++ b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/entity/TableStatus.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.entity; + +public enum TableStatus { + TODO, + COMPLETED +} diff --git a/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/repository/VirtualTOrderRepository.java b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/repository/VirtualTOrderRepository.java new file mode 100644 index 0000000000..e20e9e539f --- /dev/null +++ b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/fixture/reachability/metadata/repository/VirtualTOrderRepository.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.repository; + +import org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.entity.TOrderPOJO; +import org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.entity.TableStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.LongStream; + +public class VirtualTOrderRepository { + private final Map data = new ConcurrentHashMap<>(300, 1); + + public VirtualTOrderRepository() { + addData(0L, 100L, "Norddorf"); + addData(100L, 200L, "Bordeaux"); + addData(200L, 300L, "Somerset"); + } + + private void addData(final long startId, final long endId, final String location) { + LongStream.range(startId, endId).forEachOrdered(i -> data.put(i, new TOrderPOJO(i, location, TableStatus.TODO))); + } + + /** + * Query operations on virtual tables. + * + * @param location Virtual table location attribute + * @param limitNumber Number of items queried + * @return Deserialized object for multiple columns of table + */ + public List findTodoData(final String location, final int limitNumber) { + return data.entrySet().stream() + .limit(limitNumber) + .map(Map.Entry::getValue) + .filter(tOrderPOJO -> location.equals(tOrderPOJO.getLocation()) && TableStatus.TODO == tOrderPOJO.getTableStatus()) + .collect(Collectors.toCollection(() -> new ArrayList<>(limitNumber))); + } + + /** + * Set the tableStatus attribute of a column in the virtual table. + * + * @param id Virtual table id attribute + */ + public void setCompleted(final long id) { + data.replace(id, new TOrderPOJO(id, data.get(id).getLocation(), TableStatus.COMPLETED)); + } +} diff --git a/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/integrate/disable/DisabledJobIntegrateTest.java b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/integrate/disable/DisabledJobIntegrateTest.java index e03256e165..a5e99eca23 100644 --- a/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/integrate/disable/DisabledJobIntegrateTest.java +++ b/elasticjob-lite/elasticjob-lite-core/src/test/java/org/apache/shardingsphere/elasticjob/lite/integrate/disable/DisabledJobIntegrateTest.java @@ -42,7 +42,7 @@ public DisabledJobIntegrateTest(final TestType type) { } protected final void assertDisabledRegCenterInfo() { - Awaitility.await().atLeast(100L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> { + Awaitility.await().atLeast(1L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> { assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(getJobName()), is(3)); assertThat(JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp(), is(IpUtils.getIp())); }); diff --git a/elasticjob-lite/elasticjob-lite-spring/elasticjob-lite-spring-namespace/src/test/java/org/apache/shardingsphere/elasticjob/lite/spring/namespace/job/OneOffJobSpringNamespaceWithTypeTest.java b/elasticjob-lite/elasticjob-lite-spring/elasticjob-lite-spring-namespace/src/test/java/org/apache/shardingsphere/elasticjob/lite/spring/namespace/job/OneOffJobSpringNamespaceWithTypeTest.java index e0ae1ae17d..1dcc6dd48a 100644 --- a/elasticjob-lite/elasticjob-lite-spring/elasticjob-lite-spring-namespace/src/test/java/org/apache/shardingsphere/elasticjob/lite/spring/namespace/job/OneOffJobSpringNamespaceWithTypeTest.java +++ b/elasticjob-lite/elasticjob-lite-spring/elasticjob-lite-spring-namespace/src/test/java/org/apache/shardingsphere/elasticjob/lite/spring/namespace/job/OneOffJobSpringNamespaceWithTypeTest.java @@ -52,7 +52,7 @@ public void tearDown() { public void jobScriptWithJobTypeTest() { OneOffJobBootstrap bootstrap = applicationContext.getBean(scriptJobName, OneOffJobBootstrap.class); bootstrap.execute(); - Awaitility.await().atLeast(100L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> + Awaitility.await().atLeast(1L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertTrue(regCenter.isExisted("/" + scriptJobName + "/sharding")) ); } diff --git a/elasticjob-lite/elasticjob-lite-spring/pom.xml b/elasticjob-lite/elasticjob-lite-spring/pom.xml index 35804b4a2b..1b14b82900 100644 --- a/elasticjob-lite/elasticjob-lite-spring/pom.xml +++ b/elasticjob-lite/elasticjob-lite-spring/pom.xml @@ -32,39 +32,4 @@ elasticjob-lite-spring-boot-starter elasticjob-lite-spring-namespace - - - 2.7.10 - 5.3.26 - - - - - - org.springframework.boot - spring-boot-dependencies - ${springboot.version} - pom - import - - - org.springframework - spring-context - ${springframework.version} - provided - - - org.springframework - spring-context-support - ${springframework.version} - provided - - - org.springframework - spring-test - ${springframework.version} - test - - - diff --git a/native-image/extra-filter.json b/native-image/extra-filter.json new file mode 100644 index 0000000000..570e127b11 --- /dev/null +++ b/native-image/extra-filter.json @@ -0,0 +1,19 @@ +{ + "rules": [ + {"includeClasses": "**"}, + {"excludeClasses": "java.lang.management.**"}, + {"excludeClasses": "jdk.management.**"}, + {"excludeClasses": "com.sun.management.**"}, + {"excludeClasses": "sun.management.**"}, + {"excludeClasses": "javax.management.**"}, + {"excludeClasses": "java.**"}, + {"includeClasses": "java.util.Properties"}, + {"excludeClasses": "org.apache.zookeeper.**"}, + {"excludeClasses": "org.quartz.**"} + + ], + "regexRules": [ + {"excludeClasses": ".*fixture*.*"}, + {"excludeClasses": ".*Test*.*"} + ] +} diff --git a/native-image/user-code-filter-elasticjob-lite-core.json b/native-image/user-code-filter-elasticjob-lite-core.json new file mode 100644 index 0000000000..ddb99cf239 --- /dev/null +++ b/native-image/user-code-filter-elasticjob-lite-core.json @@ -0,0 +1,9 @@ +{ + "rules": [ + {"excludeClasses": "**"}, + {"includeClasses": "org.apache.shardingsphere.elasticjob.**"}, + {"excludeClasses": "org.apache.shardingsphere.elasticjob.lite.spring.core.**"}, + {"excludeClasses": "org.apache.shardingsphere.elasticjob.lite.spring.boot.**"}, + {"excludeClasses": "org.apache.shardingsphere.elasticjob.lite.spring.namespace.**"} + ] +} diff --git a/pom.xml b/pom.xml index 9bf61bc11d..ad08491f77 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ 4.1.97.Final 1.11.0 1.0.1 + 2.7.10 2.10.0 2.11.1 @@ -102,6 +103,7 @@ 2.4 3.1.0 1.10 + 0.9.27 @@ -181,16 +183,15 @@ ${slf4j.version} true + + ch.qos.logback + logback-core + ${logback.version} + ch.qos.logback logback-classic ${logback.version} - - - org.slf4j - slf4j-api - - commons-codec @@ -339,6 +340,13 @@ zookeeper ${zookeeper.version} + + org.springframework.boot + spring-boot-dependencies + ${springboot.version} + pom + import + @@ -721,6 +729,109 @@ + + generateMetadata + + 21 + + + + + + maven-surefire-plugin + + + org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.** + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-maven-plugin.version} + true + + + build-native + + compile-no-fork + + package + + + test-native + + test + + test + + + + + true + Conditional + + + ${user.dir}/native-image/user-code-filter-elasticjob-lite-core.json + ${user.dir}/native-image/extra-filter.json + true + + + + + main + + false + ${project.basedir}/src/main/resources/META-INF/native-image/${project.groupId}/${project.artifactId}/ + + + + + + + + + + nativeTestInElasticJob + + 21 + + + + + + maven-surefire-plugin + + + org.apache.shardingsphere.elasticjob.lite.fixture.reachability.metadata.** + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-maven-plugin.version} + true + + ${project.build.outputDirectory} + + true + + + + + test-native + + test + + test + + + + + + +