Skip to content

Commit afb0183

Browse files
ARM64 build for Test Server (#2448)
Switch graal plugin
1 parent a4c9e68 commit afb0183

File tree

12 files changed

+1451
-372
lines changed

12 files changed

+1451
-372
lines changed

.github/workflows/prepare-release.yml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ jobs:
134134
- runner: macos-13
135135
os_family: macOS
136136
arch: amd64
137+
- runner: macos-latest
138+
os_family: macOS
139+
arch: arm64
140+
- runner: ubuntu-24.04-arm
141+
os_family: linux
142+
arch: arm64
137143
- runner: windows-2019
138144
os_family: windows
139145
arch: amd64
@@ -154,8 +160,8 @@ jobs:
154160
if: matrix.os_family != 'Linux'
155161
uses: actions/setup-java@v4
156162
with:
157-
java-version: "11"
158-
distribution: "temurin"
163+
java-version: "21"
164+
distribution: "graalvm"
159165

160166
- name: Set up Gradle
161167
if: matrix.os_family != 'Linux'
@@ -164,24 +170,22 @@ jobs:
164170
- name: Build native test server (non-Docker)
165171
if: matrix.os_family != 'Linux'
166172
run: |
167-
./gradlew :temporal-test-server:build
173+
./gradlew -PnativeBuild :temporal-test-server:nativeBuild
168174
169175
- name: Build native test server (Docker)
170176
if: matrix.os_family == 'Linux'
171177
run: |
172178
docker run \
173179
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
174180
$(docker build -q ./docker/native-image) \
175-
sh -c "./gradlew :temporal-test-server:build"
181+
sh -c "./gradlew -PnativeBuild :temporal-test-server:nativeBuild"
176182
# path ends in a wildcard because on windows the file ends in '.exe'
177-
# path excludes *.txt because native-image also writes a build manifest txt file
178183
- name: Upload executable to workflow
179184
uses: actions/upload-artifact@v4
180185
with:
181186
name: ${{ matrix.os_family }}_${{ matrix.arch }}
182187
path: |
183-
temporal-test-server/build/graal/temporal-test-server*
184-
!temporal-test-server/build/graal/*.txt
188+
temporal-test-server/build/native/nativeCompile/temporal-test-server*
185189
if-no-files-found: error
186190
retention-days: 1
187191

docker/native-image/dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Use an old version of Ubuntu to build the test server to maintain compatibility with
22
# older versions of glibc, specifically glib 2.17.
33
FROM ubuntu:18.04
4-
ENV JAVA_HOME=/opt/java/openjdk
5-
COPY --from=eclipse-temurin:21 $JAVA_HOME $JAVA_HOME
4+
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java21
5+
COPY --from=ghcr.io/graalvm/jdk-community:21 $JAVA_HOME $JAVA_HOME
66
ENV PATH="${JAVA_HOME}/bin:${PATH}"
77
RUN apt-get update
88
RUN apt-get install -y git build-essential zlib1g-dev

gradle/java.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ subprojects {
66

77
java {
88
// graal only supports java 8, 11, 16, 17, 21, 23
9-
sourceCompatibility = project.hasProperty("edgeDepsTest") ? JavaVersion.VERSION_21 : JavaVersion.VERSION_1_8
10-
targetCompatibility = project.hasProperty("edgeDepsTest") ? JavaVersion.VERSION_21 : JavaVersion.VERSION_1_8
9+
sourceCompatibility = project.hasProperty("edgeDepsTest") || project.hasProperty("nativeBuild") ? JavaVersion.VERSION_21 : JavaVersion.VERSION_1_8
10+
targetCompatibility = project.hasProperty("edgeDepsTest") || project.hasProperty("nativeBuild") ? JavaVersion.VERSION_21 : JavaVersion.VERSION_1_8
1111
withJavadocJar()
1212
withSourcesJar()
1313
}
1414

1515
compileJava {
1616
options.encoding = 'UTF-8'
1717
options.compilerArgs << '-Xlint:none' << '-Xlint:deprecation' << '-Werror' << '-parameters'
18-
if (JavaVersion.current().isJava9Compatible() && !project.hasProperty("edgeDepsTest")) {
18+
if (JavaVersion.current().isJava9Compatible() && !project.hasProperty("edgeDepsTest") && !project.hasProperty("nativeBuild")) {
1919
// https://stackoverflow.com/a/43103115/525203
2020
options.compilerArgs.addAll(['--release', '8'])
2121
}
@@ -24,7 +24,7 @@ subprojects {
2424
compileTestJava {
2525
options.encoding = 'UTF-8'
2626
options.compilerArgs << '-Xlint:none' << '-Xlint:deprecation' << '-Werror' << '-parameters'
27-
if (JavaVersion.current().isJava9Compatible() && !project.hasProperty("edgeDepsTest")) {
27+
if (JavaVersion.current().isJava9Compatible() && !project.hasProperty("edgeDepsTest") && !project.hasProperty("nativeBuild")) {
2828
// https://stackoverflow.com/a/43103115/525203
2929
options.compilerArgs.addAll(['--release', '8'])
3030
}

temporal-test-server/README.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,35 @@ This service allows to run a test-only in-memory implementation of Temporal serv
1919
## To build a test server using GraalVM native-image
2020

2121
From the root of the java-sdk repo:
22-
```
23-
./gradlew :temporal-test-server:build
22+
```bash
23+
./gradlew -PnativeBuild :temporal-test-server:nativeCompile
2424
```
2525
This will give you a native executable `build/graal/temporal-test-server`. The
2626
executable requires a single argument: the port number on which it should
2727
listen.
2828

29-
## To build a test server docker image
29+
## To run the test server as a native-image through Gradle
3030

3131
From the root of the java-sdk repo:
32-
```
33-
./gradlew :temporal-test-server:docker
32+
```bash
33+
./gradlew -PnativeBuild :temporal-test-server:nativeRun
3434
```
3535

36-
This will result in a local image being built:
37-
`temporalio/temporal-test-server`.
3836

3937
## GraalVM native-image configuration
4038

4139
The GraalVM native-image compiler uses the native-image.properties file and the
4240
referenced JSON files during compilation. The JSON files are generated by
4341
running the test server java code in a JVM configured with the [GraalVM tracing
4442
agent](https://www.graalvm.org/latest/reference-manual/native-image/metadata/AutomaticMetadataCollection/) configured,
45-
e.g. with the flag
46-
`-agentlib:native-image-agent=config-output-dir=temporal-test-server/src/main/resources/META-INF/native-image/io.temporal/temporal-test-server`.
43+
44+
### To run the test server test with tracing agent through Gradle
45+
46+
```bash
47+
./gradlew -Pagent -PnativeBuild :temporal-test-server:test
48+
```
49+
50+
### Copy metadata from test run
51+
```bash
52+
./gradlew -PnativeBuild :temporal-test-server:metadataCopy --task test
53+
```

temporal-test-server/build.gradle

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
1-
buildscript {
2-
ext {
3-
// 0.11.0 and later are build on JDK 11 bytecode version
4-
graalVersion = "${JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11) ? '0.12.0' : '0.10.0'}"
5-
}
6-
}
7-
81
plugins {
92
id 'application'
10-
id 'com.palantir.graal' version "${graalVersion}"
3+
id 'org.graalvm.buildtools.native' version '0.10.6' apply false
114
id 'com.google.protobuf' version '0.9.2'
125
}
136

@@ -99,28 +92,43 @@ idea {
9992
}
10093

10194

102-
graal {
103-
outputName "temporal-test-server"
104-
mainClass application.getMainClass().get()
105-
javaVersion '17'
106-
graalVersion '22.3.1'
107-
108-
// Don't fallback to running a JVM
109-
option "--no-fallback"
110-
111-
// Signal handling so that ^C actually stops the process
112-
option "--install-exit-handlers"
113-
114-
// If we're on linux, static link everything but libc. Otherwise link
115-
// everything dynamically (note the '-' rather than '+' in fromt of
116-
// StaticExecutable)
117-
option isLinux()
118-
? "-H:+StaticExecutableWithDynamicLibC"
119-
: "-H:-StaticExecutable"
120-
}
121-
12295
def isLinux() {
123-
return System.properties['os.name'].toLowerCase().contains('linux')
96+
return System.properties['os.name'].toLowerCase().contains('linux')
12497
}
12598

126-
tasks.build.dependsOn('nativeImage')
99+
// The graalvm plugin requires we build with Java 11
100+
if (project.hasProperty("nativeBuild")) {
101+
apply plugin: 'org.graalvm.buildtools.native'
102+
103+
graalvmNative {
104+
toolchainDetection = true
105+
agent {
106+
enabled = true
107+
defaultMode = "standard"
108+
metadataCopy {
109+
outputDirectories.add("src/main/resources/META-INF/native-image/io.temporal/temporal-test-server")
110+
mergeWithExisting = false
111+
}
112+
113+
}
114+
binaries {
115+
main {
116+
mainClass = application.getMainClass().get()
117+
sharedLibrary = false
118+
// Signal handling so that ^C actually stops the process
119+
buildArgs.add("--install-exit-handlers")
120+
// If we're on linux, static link everything but libc. Otherwise link
121+
// everything dynamically (note the '-' rather than '+' in front of
122+
// StaticExecutable)
123+
buildArgs.add(isLinux() ? "-H:+StaticExecutableWithDynamicLibC": "-H:-StaticExecutable")
124+
buildArgs.add("-H:+UnlockExperimentalVMOptions")
125+
buildArgs.add("-O4")
126+
127+
runtimeArgs.add("7233")
128+
}
129+
}
130+
binaries.all {
131+
verbose = true
132+
}
133+
}
134+
}

temporal-test-server/src/main/resources/META-INF/native-image/io.temporal/temporal-test-server/jni-config.json

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,22 @@
99
},
1010
{
1111
"name":"java.lang.String",
12-
"methods":[
13-
{"name":"lastIndexOf","parameterTypes":["int"] },
14-
{"name":"substring","parameterTypes":["int"] }
15-
]
12+
"methods":[{"name":"lastIndexOf","parameterTypes":["int"] }, {"name":"substring","parameterTypes":["int"] }]
1613
},
1714
{
1815
"name":"java.lang.System",
19-
"methods":[
20-
{"name":"getProperty","parameterTypes":["java.lang.String"] },
21-
{"name":"setProperty","parameterTypes":["java.lang.String","java.lang.String"] }
22-
]
16+
"methods":[{"name":"getProperty","parameterTypes":["java.lang.String"] }, {"name":"setProperty","parameterTypes":["java.lang.String","java.lang.String"] }]
17+
},
18+
{
19+
"name":"sun.instrument.InstrumentationImpl",
20+
"methods":[{"name":"<init>","parameterTypes":["long","boolean","boolean","boolean"] }, {"name":"loadClassAndCallAgentmain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"loadClassAndCallPremain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"transform","parameterTypes":["java.lang.Module","java.lang.ClassLoader","java.lang.String","java.lang.Class","java.security.ProtectionDomain","byte[]","boolean"] }]
2321
},
2422
{
2523
"name":"sun.management.VMManagementImpl",
26-
"fields":[
27-
{"name":"compTimeMonitoringSupport"},
28-
{"name":"currentThreadCpuTimeSupport"},
29-
{"name":"objectMonitorUsageSupport"},
30-
{"name":"otherThreadCpuTimeSupport"},
31-
{"name":"remoteDiagnosticCommandsSupport"},
32-
{"name":"synchronizerUsageSupport"},
33-
{"name":"threadAllocatedMemorySupport"},
34-
{"name":"threadContentionMonitoringSupport"}
35-
]
24+
"fields":[{"name":"compTimeMonitoringSupport"}, {"name":"currentThreadCpuTimeSupport"}, {"name":"objectMonitorUsageSupport"}, {"name":"otherThreadCpuTimeSupport"}, {"name":"remoteDiagnosticCommandsSupport"}, {"name":"synchronizerUsageSupport"}, {"name":"threadAllocatedMemorySupport"}, {"name":"threadContentionMonitoringSupport"}]
25+
},
26+
{
27+
"name":"worker.org.gradle.process.internal.worker.GradleWorkerMain",
28+
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
3629
}
37-
]
30+
]

temporal-test-server/src/main/resources/META-INF/native-image/io.temporal/temporal-test-server/native-image.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
# limitations under the License.
1919
#
2020

21-
Args = -H:DynamicProxyConfigurationResources=${.}/proxy-config.json \
21+
Args = -H:+UnlockExperimentalVMOptions \
22+
-H:DynamicProxyConfigurationResources=${.}/proxy-config.json \
2223
-H:JNIConfigurationResources=${.}/jni-config.json \
2324
-H:ReflectionConfigurationResources=${.}/reflect-config.json \
2425
-H:ResourceConfigurationResources=${.}/resource-config.json \

temporal-test-server/src/main/resources/META-INF/native-image/io.temporal/temporal-test-server/predefined-classes-config.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@
55
]
66
}
77
]
8-
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,113 @@
11
[
2-
]
2+
{
3+
"interfaces":["io.temporal.client.WorkflowClient"]
4+
},
5+
{
6+
"interfaces":["io.temporal.serviceclient.OperatorServiceStubs"]
7+
},
8+
{
9+
"interfaces":["io.temporal.serviceclient.TestServiceStubs"]
10+
},
11+
{
12+
"interfaces":["io.temporal.serviceclient.WorkflowServiceStubs"]
13+
},
14+
{
15+
"interfaces":["io.temporal.testserver.functional.DescribeWorkflowExecutionTest$TestDescribeActivity","io.temporal.internal.sync.AsyncInternal$AsyncMarker"]
16+
},
17+
{
18+
"interfaces":["io.temporal.testserver.functional.DescribeWorkflowExecutionTest$TestDescribeWorkflow","io.temporal.internal.sync.StubMarker","io.temporal.internal.sync.AsyncInternal$AsyncMarker"]
19+
},
20+
{
21+
"interfaces":["io.temporal.testserver.functional.common.TestActivities$ActivityReturnsString","io.temporal.internal.sync.AsyncInternal$AsyncMarker"]
22+
},
23+
{
24+
"interfaces":["io.temporal.testserver.functional.common.TestWorkflows$PrimitiveChildWorkflow","io.temporal.internal.sync.StubMarker","io.temporal.internal.sync.AsyncInternal$AsyncMarker"]
25+
},
26+
{
27+
"interfaces":["io.temporal.testserver.functional.common.TestWorkflows$PrimitiveWorkflow","io.temporal.internal.sync.StubMarker"]
28+
},
29+
{
30+
"interfaces":["io.temporal.testserver.functional.common.TestWorkflows$WorkflowReturnsString","io.temporal.internal.sync.StubMarker"]
31+
},
32+
{
33+
"interfaces":["io.temporal.testserver.functional.common.TestWorkflows$WorkflowTakesBool","io.temporal.internal.sync.StubMarker"]
34+
},
35+
{
36+
"interfaces":["io.temporal.testserver.functional.common.TestWorkflows$WorkflowWithSignal","io.temporal.internal.sync.StubMarker"]
37+
},
38+
{
39+
"interfaces":["io.temporal.testserver.functional.common.TestWorkflows$WorkflowWithUpdate","io.temporal.internal.sync.StubMarker"]
40+
},
41+
{
42+
"interfaces":["io.temporal.testserver.functional.timeskipping.SleepingActivity","io.temporal.internal.sync.AsyncInternal$AsyncMarker"]
43+
},
44+
{
45+
"interfaces":["net.bytebuddy.description.method.MethodDescription$InDefinedShape$AbstractBase$Executable"]
46+
},
47+
{
48+
"interfaces":["net.bytebuddy.description.method.ParameterDescription$ForLoadedParameter$Parameter"]
49+
},
50+
{
51+
"interfaces":["net.bytebuddy.description.method.ParameterList$ForLoadedExecutable$Executable"]
52+
},
53+
{
54+
"interfaces":["net.bytebuddy.description.type.TypeDefinition$Sort$AnnotatedType"]
55+
},
56+
{
57+
"interfaces":["net.bytebuddy.description.type.TypeDescription"]
58+
},
59+
{
60+
"interfaces":["net.bytebuddy.description.type.TypeDescription$ForLoadedType$Dispatcher"]
61+
},
62+
{
63+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic"]
64+
},
65+
{
66+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedExecutableExceptionType$Dispatcher"]
67+
},
68+
{
69+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedExecutableParameterType$Dispatcher"]
70+
},
71+
{
72+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedField$Dispatcher"]
73+
},
74+
{
75+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$Delegator$ForLoadedMethodReturnType$Dispatcher"]
76+
},
77+
{
78+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForComponentType$AnnotatedParameterizedType"]
79+
},
80+
{
81+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForTypeArgument$AnnotatedParameterizedType"]
82+
},
83+
{
84+
"interfaces":["net.bytebuddy.description.type.TypeDescription$Generic$AnnotationReader$ForWildcardUpperBoundType$AnnotatedWildcardType"]
85+
},
86+
{
87+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher"]
88+
},
89+
{
90+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfClassDesc"]
91+
},
92+
{
93+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfDirectMethodHandleDesc"]
94+
},
95+
{
96+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfDirectMethodHandleDesc$ForKind"]
97+
},
98+
{
99+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfDynamicConstantDesc"]
100+
},
101+
{
102+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfMethodHandleDesc"]
103+
},
104+
{
105+
"interfaces":["net.bytebuddy.utility.JavaConstant$Simple$Dispatcher$OfMethodTypeDesc"]
106+
},
107+
{
108+
"interfaces":["net.bytebuddy.utility.JavaModule$Module"]
109+
},
110+
{
111+
"interfaces":["net.bytebuddy.utility.JavaModule$Resolver"]
112+
}
113+
]

0 commit comments

Comments
 (0)