Skip to content

Commit 2cc1296

Browse files
Shared core support using Panama (only Java 23+)
1 parent a7cc8be commit 2cc1296

78 files changed

Lines changed: 5859 additions & 879 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dependency-submission.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@ jobs:
1818
with:
1919
distribution: 'temurin'
2020
java-version: 17
21+
- name: Install Rust toolchain
22+
uses: actions-rust-lang/setup-rust-toolchain@v1
2123
- name: Generate and submit dependency graph
2224
uses: gradle/actions/dependency-submission@v4

.github/workflows/docker.yaml

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@ jobs:
1616
sdk-test-docker:
1717
if: github.repository_owner == 'restatedev'
1818
runs-on: warp-ubuntu-latest-x64-4x
19-
name: "Create test-services Docker Image"
20-
19+
name: "Create test-services Docker Image (JRE ${{ matrix.jreVersion }})"
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
# 17 & 21 -> pure-Java state machine (17 also published as :main); 25 -> Panama/FFM state machine.
24+
jreVersion: [ 17, 21, 25 ]
25+
2126
steps:
2227
- uses: actions/checkout@v4
2328
with:
@@ -32,17 +37,25 @@ jobs:
3237
- name: Setup Gradle
3338
uses: gradle/actions/setup-gradle@v4
3439

40+
- name: Install Rust toolchain
41+
uses: actions-rust-lang/setup-rust-toolchain@v1
42+
3543
- name: Log into GitHub container registry
3644
uses: docker/login-action@v2
3745
with:
3846
registry: ${{ env.GHCR_REGISTRY }}
3947
username: ${{ env.GHCR_REGISTRY_USERNAME }}
4048
password: ${{ env.GHCR_REGISTRY_TOKEN }}
4149

42-
- name: Build restatedev/test-services-java image
43-
run: ./gradlew -Djib.console=plain :test-services:jibDockerBuild
50+
- name: Build restatedev/test-services-java image (JRE ${{ matrix.jreVersion }})
51+
run: ./gradlew -Djib.console=plain :test-services:jibDockerBuild -PtestServicesJre=${{ matrix.jreVersion }}
4452

45-
- name: Push restatedev/test-services-java:main image
53+
- name: Push restatedev/test-services-java image
4654
run: |
47-
docker tag restatedev/test-services-java ghcr.io/restatedev/test-services-java:main
48-
docker push ghcr.io/restatedev/test-services-java:main
55+
docker tag restatedev/test-services-java ghcr.io/restatedev/test-services-java:main-jre${{ matrix.jreVersion }}
56+
docker push ghcr.io/restatedev/test-services-java:main-jre${{ matrix.jreVersion }}
57+
# The minimum-Java (pure-Java state machine) image is also the default :main tag.
58+
if [ "${{ matrix.jreVersion }}" = "17" ]; then
59+
docker tag restatedev/test-services-java ghcr.io/restatedev/test-services-java:main
60+
docker push ghcr.io/restatedev/test-services-java:main
61+
fi

.github/workflows/integration.yaml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ jobs:
6262
sdk-test-suite:
6363
if: github.repository_owner == 'restatedev'
6464
runs-on: warp-ubuntu-latest-x64-4x
65-
name: "Features integration test"
65+
name: "Features integration test (JRE ${{ matrix.jreVersion }})"
66+
strategy:
67+
fail-fast: false
68+
matrix:
69+
# 17 & 21 exercise the pure-Java state machine; 25 activates the Panama/FFM state machine.
70+
# When an external serviceImage is supplied, the build is skipped and both entries run it.
71+
jreVersion: [ 17, 21, 25 ]
6672
permissions:
6773
contents: read
6874
issues: read
@@ -123,9 +129,13 @@ jobs:
123129
if: ${{ inputs.serviceImage == '' }}
124130
uses: gradle/actions/setup-gradle@v4
125131

132+
- name: Install Rust toolchain
133+
if: ${{ inputs.serviceImage == '' }}
134+
uses: actions-rust-lang/setup-rust-toolchain@v1
135+
126136
- name: Build restatedev/test-services-java image
127137
if: ${{ inputs.serviceImage == '' }}
128-
run: ./gradlew -Djib.console=plain :test-services:jibDockerBuild
138+
run: ./gradlew -Djib.console=plain :test-services:jibDockerBuild -PtestServicesJre=${{ matrix.jreVersion }}
129139

130140
# Pre-emptively pull the test-services image to avoid affecting execution time
131141
- name: Pull test services image
@@ -135,9 +145,9 @@ jobs:
135145

136146
- name: Run test tool
137147
continue-on-error: ${{ inputs.continueOnError == 'true' }}
138-
uses: restatedev/e2e/sdk-tests@v1.0
148+
uses: restatedev/e2e/sdk-tests@v2.1
139149
with:
140150
envVars: ${{ inputs.envVars }}
141-
testArtifactOutput: ${{ inputs.testArtifactOutput != '' && inputs.testArtifactOutput || 'sdk-java-integration-test-report' }}
151+
testArtifactOutput: ${{ inputs.testArtifactOutput != '' && format('{0}-jre{1}', inputs.testArtifactOutput, matrix.jreVersion) || format('sdk-java-integration-test-report-jre{0}', matrix.jreVersion) }}
142152
restateContainerImage: ${{ inputs.restateCommit != '' && 'localhost/restatedev/restate-commit-download:latest' || (inputs.restateImage != '' && inputs.restateImage || 'ghcr.io/restatedev/restate:main') }}
143153
serviceContainerImage: ${{ inputs.serviceImage != '' && inputs.serviceImage || 'restatedev/test-services-java' }}

.github/workflows/native.yaml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Native build
2+
3+
# Cross-compiles the Rust shared-core wrapper (sdk-core/src/main/rust) for every supported
4+
# platform, smoke-tests the produced library, and uploads it as an artifact. The release pipeline
5+
# downloads these artifacts and overlays them into the single (uber) sdk-core jar.
6+
7+
on:
8+
pull_request:
9+
paths:
10+
- 'sdk-core/src/main/rust/**'
11+
- '.github/workflows/native.yaml'
12+
workflow_dispatch:
13+
workflow_call:
14+
15+
jobs:
16+
build:
17+
name: "Build native (${{ matrix.target }})"
18+
runs-on: ${{ matrix.runner }}
19+
timeout-minutes: 30
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
include:
24+
- target: x86_64-unknown-linux-gnu
25+
runner: ubuntu-latest
26+
cross: false
27+
- target: aarch64-unknown-linux-gnu
28+
runner: ubuntu-latest
29+
cross: true
30+
- target: x86_64-unknown-linux-musl
31+
runner: ubuntu-latest
32+
cross: true
33+
- target: aarch64-unknown-linux-musl
34+
runner: ubuntu-latest
35+
cross: true
36+
- target: x86_64-apple-darwin
37+
runner: macos-13
38+
cross: false
39+
- target: aarch64-apple-darwin
40+
runner: macos-14
41+
cross: false
42+
steps:
43+
- uses: actions/checkout@v4
44+
45+
- name: Install Rust toolchain
46+
uses: actions-rust-lang/setup-rust-toolchain@v1
47+
with:
48+
target: ${{ matrix.target }}
49+
50+
- name: Install cross
51+
if: ${{ matrix.cross }}
52+
run: cargo install cross --git https://github.com/cross-rs/cross --locked
53+
54+
- name: Build cdylib
55+
working-directory: sdk-core/src/main/rust
56+
run: |
57+
if [ "${{ matrix.cross }}" = "true" ]; then
58+
cross build --release --target ${{ matrix.target }}
59+
else
60+
cargo build --release --target ${{ matrix.target }}
61+
fi
62+
63+
- name: Locate library
64+
id: lib
65+
working-directory: sdk-core/src/main/rust
66+
run: |
67+
dir="target/${{ matrix.target }}/release"
68+
file=$(ls "$dir"/librestate_sdk_core.so "$dir"/librestate_sdk_core.dylib 2>/dev/null | head -1)
69+
if [ -z "$file" ]; then echo "no library produced for ${{ matrix.target }}"; exit 1; fi
70+
echo "path=sdk-core/src/main/rust/$file" >> "$GITHUB_OUTPUT"
71+
echo "file=$file" >> "$GITHUB_OUTPUT"
72+
73+
- name: Smoke test (exported C symbols present)
74+
working-directory: sdk-core/src/main/rust
75+
run: |
76+
f="${{ steps.lib.outputs.file }}"
77+
# Linux uses `nm -D` (no symbol prefix); macOS uses `nm -gU` (leading underscore).
78+
if [ "$RUNNER_OS" = "macOS" ]; then list="nm -gU"; pre="_"; else list="nm -D"; pre=""; fi
79+
for sym in init vm_new vm_free free_buffer vm_sys_call vm_take_notification; do
80+
$list "$f" 2>/dev/null | grep -qE "[ ]${pre}${sym}$" || { echo "missing exported symbol: $sym"; exit 1; }
81+
done
82+
echo "All expected symbols present in $f"
83+
84+
- name: Upload native library
85+
uses: actions/upload-artifact@v4
86+
with:
87+
name: native-${{ matrix.target }}
88+
path: ${{ steps.lib.outputs.path }}
89+
if-no-files-found: error

.github/workflows/release-docs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ jobs:
3131
java-version: '21'
3232
- name: Setup Gradle
3333
uses: gradle/actions/setup-gradle@v4
34+
- name: Install Rust toolchain
35+
uses: actions-rust-lang/setup-rust-toolchain@v1
3436

3537
- name: Build Javadocs
3638
run: gradle :sdk-aggregated-javadocs:javadoc

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ jobs:
2020
- name: Setup Gradle
2121
uses: gradle/actions/setup-gradle@v4
2222

23+
- name: Install Rust toolchain
24+
uses: actions-rust-lang/setup-rust-toolchain@v1
25+
2326
# Retrieve the version of the SDK
2427
- name: Install dasel
2528
run: curl -sSLf "$(curl -sSLf https://api.github.com/repos/tomwright/dasel/releases/latest | grep browser_download_url | grep linux_amd64 | grep -v .gz | cut -d\" -f 4)" -L -o dasel && chmod +x dasel && mv ./dasel /usr/local/bin/dasel

.github/workflows/tests.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
- name: Setup Gradle
2828
uses: gradle/actions/setup-gradle@v4
2929

30+
- name: Install Rust toolchain
31+
uses: actions-rust-lang/setup-rust-toolchain@v1
32+
3033
- name: Pull Restate docker image
3134
run: docker pull ghcr.io/restatedev/restate:main
3235

@@ -54,6 +57,8 @@ jobs:
5457
java-version: '21'
5558
- name: Setup Gradle
5659
uses: gradle/actions/setup-gradle@v4
60+
- name: Install Rust toolchain
61+
uses: actions-rust-lang/setup-rust-toolchain@v1
5762

5863
- name: Build Javadocs
5964
run: gradle :sdk-aggregated-javadocs:javadoc

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ build
3737
kls_database.db
3838
.kotlin
3939

40-
.restate
40+
.restate
41+
/sdk-core/src/main/rust/target/

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ This SDK features:
2929
## Using the SDK
3030

3131
### Prerequisites
32-
- JDK >= 17
32+
- JDK >= 17 (JDK >= 23 recommended — required for the latest Restate features; see [Native access on JDK 23+](#native-access-on-jdk-23))
3333

3434
### tl;dr Use project templates
3535

@@ -208,6 +208,46 @@ You can now upload the generated Jar in AWS Lambda, and configure `MyLambdaHandl
208208

209209
### Additional setup
210210

211+
#### Native access on JDK 23+
212+
213+
On JDK 23 and later the SDK runs its state machine through the native Restate shared-core library, via
214+
the Java Foreign Function & Memory API. **This is required to support the latest Restate features.** On
215+
older JDKs the SDK falls back to a pure-Java state machine, which is **deprecated and will be removed in
216+
a future release** — so running on JDK 23+ is strongly recommended.
217+
218+
Using the native library requires _native access_ to be enabled for the application. If it isn't, the
219+
SDK still works but the JVM prints a one-time warning at startup (e.g. _"A restricted method ... has
220+
been called ... Use --enable-native-access=ALL-UNNAMED to avoid a warning"_), and a future JDK will turn
221+
that warning into an error — so it's worth enabling.
222+
223+
The cleanest way to enable it **without a command-line flag** is to add this attribute to the manifest
224+
of your application's runnable (fat) jar — for example with the Gradle Shadow plugin:
225+
226+
```kotlin
227+
tasks.shadowJar {
228+
manifest { attributes("Enable-Native-Access" to "ALL-UNNAMED") }
229+
}
230+
```
231+
232+
(`ALL-UNNAMED` is the only accepted value.) For launchers that don't run the app via `java -jar`
233+
(custom entrypoints, containers, `java -cp`), pass `--enable-native-access=ALL-UNNAMED` directly or via
234+
the `JDK_JAVA_OPTIONS` environment variable.
235+
236+
If you'd rather grant native access **selectively** (the integrity-friendly approach recommended by the
237+
JDK) instead of to the whole class path, put the SDK jars on the **module path** and enable access only
238+
for the module that performs it — `sdk-core` publishes the stable automatic-module name
239+
`dev.restate.sdk.core`:
240+
241+
```
242+
java --module-path libs --enable-native-access=dev.restate.sdk.core ...
243+
```
244+
245+
(`sdk-core` works unchanged on the class path too; the module name is simply ignored there.)
246+
247+
To force the pure-Java state machine instead (no native access needed), set
248+
`-Ddev.restate.sdk.statemachine.disableFfm=true`. On JDK < 23 the pure-Java state machine is always
249+
used.
250+
211251
#### Logging
212252

213253
The SDK uses log4j2 as logging facade, to configure it add the file `resources/log4j2.properties`:

buildSrc/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repositories {
99

1010

1111
dependencies {
12-
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.10")
13-
implementation("org.jetbrains.kotlin:kotlin-serialization:2.2.10")
12+
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.0")
13+
implementation("org.jetbrains.kotlin:kotlin-serialization:2.3.0")
1414
implementation("com.diffplug.spotless:spotless-plugin-gradle:8.2.0")
1515
}

0 commit comments

Comments
 (0)