Skip to content

Commit a468292

Browse files
WIP before removal
1 parent 69e1507 commit a468292

12 files changed

Lines changed: 2793 additions & 69 deletions

File tree

.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/

gradle/libs.versions.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,32 @@
213213
[libraries.victools-jsonschema-module-jackson.version]
214214
ref = 'victools-json-schema'
215215

216+
[libraries.chicory-runtime]
217+
module = 'com.dylibso.chicory:runtime'
218+
219+
[libraries.chicory-runtime.version]
220+
ref = 'chicory'
221+
222+
[libraries.chicory-annotations]
223+
module = 'com.dylibso.chicory:annotations'
224+
225+
[libraries.chicory-annotations.version]
226+
ref = 'chicory'
227+
228+
[libraries.chicory-annotations-processor]
229+
module = 'com.dylibso.chicory:annotations-processor'
230+
231+
[libraries.chicory-annotations-processor.version]
232+
ref = 'chicory'
233+
234+
[libraries.jackson-cbor]
235+
module = 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor'
236+
237+
[libraries.jackson-cbor.version]
238+
ref = 'jackson'
239+
216240
[plugins]
241+
wasm2class = 'at.released.wasm2class.plugin:0.5.0'
217242
aggregate-javadoc = 'io.freefair.aggregate-javadoc:8.14'
218243
dependency-license-report = 'com.github.jk1.dependency-license-report:2.9'
219244
dokka = 'org.jetbrains.dokka:1.9.20'
@@ -233,6 +258,7 @@
233258
ref = 'ksp'
234259

235260
[versions]
261+
chicory = '1.7.5'
236262
jackson = '2.19.4'
237263
junit = '5.14.1'
238264
kotlinx-coroutines = '1.10.2'

sdk-core/build.gradle.kts

Lines changed: 122 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,107 @@ plugins {
88
`kotlin-conventions`
99
`library-publishing-conventions`
1010
alias(libs.plugins.jsonschema2pojo)
11-
alias(libs.plugins.protobuf)
12-
alias(libs.plugins.shadow)
1311
alias(libs.plugins.ksp)
12+
// Chicory AOT: compile .wasm to JVM bytecode at build time
13+
id("at.released.wasm2class.plugin") version "0.5.0"
1414

1515
// https://github.com/gradle/gradle/issues/20084#issuecomment-1060822638
1616
id(libs.plugins.spotless.get().pluginId) apply false
1717
}
1818

1919
description = "Restate SDK Core"
2020

21+
// ---------------------------------------------------------------------------
22+
// Rust WASM build pipeline (merged from sdk-shared-core)
23+
// ---------------------------------------------------------------------------
24+
25+
val rustSrcDir = file("src/main/rust")
26+
val wasmReleaseDir = file("$rustSrcDir/target/wasm32-unknown-unknown/release")
27+
val wasmFile = file("$wasmReleaseDir/restate_sdk_shared_core_wasm.wasm")
28+
val wasmResourceDir = layout.buildDirectory.dir("wasm-resource")
29+
val wasmResourceFile = wasmResourceDir.map { it.file("restate_sdk_shared_core_wasm.wasm") }
30+
31+
val compileRustToWasm by
32+
tasks.registering(Exec::class) {
33+
group = "build"
34+
description = "Compile the Rust WASM wrapper crate"
35+
workingDir = rustSrcDir
36+
commandLine("cargo", "build", "--target", "wasm32-unknown-unknown", "--release")
37+
inputs.dir("$rustSrcDir/src")
38+
inputs.file("$rustSrcDir/Cargo.toml")
39+
outputs.file(wasmFile)
40+
}
41+
42+
val copyWasm by
43+
tasks.registering(Copy::class) {
44+
group = "build"
45+
dependsOn(compileRustToWasm)
46+
from(wasmFile)
47+
into(wasmResourceDir)
48+
}
49+
50+
// Chicory AOT: compile .wasm → JVM bytecode
51+
wasm2class {
52+
modules {
53+
targetPackage = "dev.restate.sdk.core.sharedcore.generated"
54+
create("SharedCoreWasm") { wasm = wasmResourceFile }
55+
}
56+
}
57+
58+
tasks.named("precompileWasm2Class") { dependsOn(copyWasm) }
59+
60+
tasks.named("processResources") { dependsOn(copyWasm) }
61+
62+
tasks.withType<KotlinCompile>().configureEach {
63+
mustRunAfter(generateWasmMarker, "precompileWasm2Class")
64+
}
65+
66+
// Generate the @WasmModuleInterface marker class with the absolute wasm file URI so the
67+
// Chicory annotation processor can find it at compile time (it uses StandardLocation.CLASS_OUTPUT
68+
// which is not reliable cross-tool, so a file: URI works around that).
69+
val generatedWasmMarkerDir = layout.buildDirectory.dir("generated-wasm-marker")
70+
71+
val generateWasmMarker by
72+
tasks.registering {
73+
group = "build"
74+
dependsOn(copyWasm)
75+
inputs.file(wasmResourceFile)
76+
outputs.dir(generatedWasmMarkerDir)
77+
doLast {
78+
val wasmUri = wasmResourceFile.get().asFile.toURI().toString()
79+
val content =
80+
"""
81+
// AUTO-GENERATED — do not edit. Regenerated by generateWasmMarker Gradle task.
82+
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
83+
//
84+
// This file is part of the Restate Java SDK,
85+
// which is released under the MIT license.
86+
package dev.restate.sdk.core.sharedcore;
87+
88+
import com.dylibso.chicory.annotations.WasmModuleInterface;
89+
90+
/**
91+
* Marker class processed by Chicory's annotation processor. Generates
92+
* {@code SharedCoreWasm_ModuleExports} (typed wrapper for all WASM exports).
93+
*/
94+
@WasmModuleInterface("$wasmUri")
95+
public final class SharedCoreWasm {}
96+
"""
97+
.trimIndent() + "\n"
98+
val out =
99+
generatedWasmMarkerDir
100+
.get()
101+
.file("dev/restate/sdk/core/sharedcore/SharedCoreWasm.java")
102+
.asFile
103+
out.parentFile.mkdirs()
104+
out.writeText(content)
105+
}
106+
}
107+
108+
// ---------------------------------------------------------------------------
109+
// Dependency configurations
110+
// ---------------------------------------------------------------------------
111+
21112
val shade by configurations.creating
22113
val implementation by configurations.getting
23114

@@ -30,17 +121,21 @@ api.extendsFrom(shade)
30121
dependencies {
31122
compileOnly(libs.jspecify)
32123

33-
shadow(project(":sdk-common"))
124+
// Chicory annotation processor (@WasmModuleInterface, @HostModule)
125+
compileOnly(libs.chicory.annotations)
126+
annotationProcessor(libs.chicory.annotations.processor)
34127

35-
shadow(libs.log4j.api)
36-
shadow(libs.opentelemetry.api)
128+
implementation(project(":sdk-common"))
129+
implementation(libs.log4j.api)
130+
implementation(libs.opentelemetry.api)
37131

38132
// We need this for the manifest
39-
shadow(libs.jackson.annotations)
40-
shadow(libs.jackson.databind)
133+
implementation(libs.jackson.annotations)
134+
implementation(libs.jackson.databind)
41135

42-
// We shade protobuf java
43-
shade(libs.protobuf.java)
136+
// Chicory runtime + Jackson CBOR for the WASM bridge — shaded into the jar
137+
implementation(libs.chicory.runtime)
138+
implementation(libs.jackson.cbor)
44139

45140
// We don't want a hard-dependency on it
46141
compileOnly(libs.log4j.core)
@@ -55,10 +150,11 @@ dependencies {
55150
testImplementation(project(":sdk-api"))
56151
testImplementation(project(":sdk-api-kotlin"))
57152
testImplementation(project(":sdk-http-vertx"))
58-
testImplementation(project(":sdk-lambda"))
59153
testImplementation(libs.jackson.annotations)
60154
testImplementation(libs.jackson.databind)
155+
testImplementation(libs.jackson.cbor)
61156
testImplementation(libs.opentelemetry.api)
157+
testImplementation(libs.chicory.runtime)
62158
testImplementation(libs.protobuf.java)
63159
testImplementation(libs.mutiny)
64160
testImplementation(libs.junit.jupiter)
@@ -71,39 +167,42 @@ dependencies {
71167
testRuntimeOnly(libs.junit.platform.launcher)
72168
}
73169

74-
// Configure source sets for protobuf plugin and jsonschema2pojo
170+
// ---------------------------------------------------------------------------
171+
// Source sets
172+
// ---------------------------------------------------------------------------
173+
75174
val generatedJ2SPDir = layout.buildDirectory.dir("generated/j2sp")
76175

77176
sourceSets {
78177
main {
79178
java.srcDir(generatedJ2SPDir)
80-
proto { srcDirs("src/main/service-protocol") }
179+
java.srcDir(generatedWasmMarkerDir)
180+
proto { srcDirs("src/main/service-protocol") } // TODO(Phase3): remove
181+
resources.srcDir(wasmResourceDir)
81182
}
82183
}
83184

84-
// Configure jsonSchema2Pojo
185+
// ---------------------------------------------------------------------------
186+
// jsonSchema2Pojo
187+
// ---------------------------------------------------------------------------
188+
85189
jsonSchema2Pojo {
86190
setSource(files("$projectDir/src/main/service-protocol/endpoint_manifest_schema.json"))
87191
targetPackage = "dev.restate.sdk.core.generated.manifest"
88192
targetDirectory = generatedJ2SPDir.get().asFile
89-
90193
useLongIntegers = true
91194
includeSetters = true
92195
includeGetters = true
93196
generateBuilders = true
94197
}
95198

96-
// Configure protobuf
97-
98-
val protobufVersion = libs.versions.protobuf.get()
99-
100-
protobuf { protoc { artifact = "com.google.protobuf:protoc:$protobufVersion" } }
101-
102-
// Make sure task dependencies are correct
199+
// ---------------------------------------------------------------------------
200+
// Task wiring
201+
// ---------------------------------------------------------------------------
103202

104203
tasks {
105204
withType<JavaCompile> {
106-
dependsOn(generateJsonSchema2Pojo, generateProto)
205+
dependsOn(generateJsonSchema2Pojo, generateProto, generateWasmMarker, "precompileWasm2Class")
107206

108207
val disabledClassesCodegen =
109208
listOf(
@@ -129,25 +228,9 @@ tasks {
129228
}
130229
withType<KotlinCompile>().configureEach { dependsOn(generateJsonSchema2Pojo, generateProto) }
131230
withType<org.gradle.jvm.tasks.Jar>().configureEach {
132-
dependsOn(generateJsonSchema2Pojo, generateProto)
231+
dependsOn(generateJsonSchema2Pojo, generateProto, generateWasmMarker)
133232
}
134233
withType<AbstractDokkaTask>().configureEach { dependsOn(generateJsonSchema2Pojo, generateProto) }
135-
136-
getByName("jar") {
137-
enabled = false
138-
dependsOn(shadowJar)
139-
}
140-
141-
shadowJar {
142-
configurations = listOf(shade)
143-
enableRelocation = true
144-
archiveClassifier = null
145-
relocate("com.google.protobuf", "dev.restate.shaded.com.google.protobuf")
146-
dependencies {
147-
project.configurations["shadow"].allDependencies.forEach { exclude(dependency(it)) }
148-
exclude("**/google/protobuf/*.proto")
149-
}
150-
}
151234
}
152235

153236
ksp {
@@ -169,20 +252,3 @@ ksp {
169252
)
170253
arg("dev.restate.codegen.disabledClasses", disabledClassesCodegen.joinToString(","))
171254
}
172-
173-
// spotless configuration for protobuf
174-
175-
configure<com.diffplug.gradle.spotless.SpotlessExtension> {
176-
format("proto") {
177-
target("**/*.proto")
178-
179-
// Exclude proto and service-protocol directories because those get the license header from
180-
// their repos.
181-
targetExclude(
182-
fileTree("$rootDir/sdk-common/src/main/proto") { include("**/*.*") },
183-
fileTree("$rootDir/sdk-core/src/main/service-protocol") { include("**/*.*") },
184-
)
185-
186-
licenseHeaderFile("$rootDir/config/license-header", "syntax")
187-
}
188-
}

sdk-core/src/main/java/dev/restate/sdk/core/HandlerContextImpl.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,11 +441,9 @@ private void pollAsyncResultInner(AsyncResultInternal<?> asyncResult) {
441441

442442
if (response instanceof StateMachine.DoProgressResponse.AnyCompleted) {
443443
// Let it loop now
444-
} else if (response instanceof StateMachine.DoProgressResponse.ReadFromInput
445-
|| response instanceof StateMachine.DoProgressResponse.WaitingPendingRun) {
446-
this.stateMachine.onNextEvent(
447-
() -> this.pollAsyncResultInner(asyncResult),
448-
response instanceof StateMachine.DoProgressResponse.ReadFromInput);
444+
} else if (response instanceof StateMachine.DoProgressResponse.WaitExternalProgress
445+
|| response instanceof StateMachine.DoProgressResponse.CancelSignalReceived) {
446+
this.stateMachine.onNextEvent(() -> this.pollAsyncResultInner(asyncResult), true);
449447
return;
450448
} else if (response instanceof StateMachine.DoProgressResponse.ExecuteRun) {
451449
triggerScheduledRun(((StateMachine.DoProgressResponse.ExecuteRun) response).handle());
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
2+
//
3+
// This file is part of the Restate Java SDK,
4+
// which is released under the MIT license.
5+
//
6+
// You can find a copy of the license in file LICENSE in the root
7+
// directory of this repository or package, or at
8+
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
9+
package dev.restate.sdk.core.sharedcore;
10+
11+
import com.dylibso.chicory.annotations.HostModule;
12+
import com.dylibso.chicory.annotations.WasmExport;
13+
import com.dylibso.chicory.runtime.HostFunction;
14+
import com.dylibso.chicory.runtime.Memory;
15+
import org.apache.logging.log4j.LogManager;
16+
import org.apache.logging.log4j.Logger;
17+
18+
/**
19+
* Host module that satisfies the {@code env} imports required by the Rust WASM crate.
20+
*
21+
* <p>The Rust side imports a single {@code log} function from the {@code env} module and routes all
22+
* {@code tracing} output through it. This class bridges those calls to Log4j.
23+
*/
24+
@HostModule("env")
25+
public final class SharedCoreImports {
26+
27+
private static final Logger LOG = LogManager.getLogger("restate.sdk.shared_core");
28+
29+
@WasmExport
30+
public void log(Memory memory, int level, int ptr, int len) {
31+
if (len <= 0) {
32+
return;
33+
}
34+
String message = memory.readString(ptr, len);
35+
switch (level) {
36+
case 0 -> LOG.trace(message); // TRACE
37+
case 1 -> LOG.debug(message); // DEBUG
38+
case 2 -> LOG.info(message); // INFO
39+
case 3 -> LOG.warn(message); // WARN
40+
default -> LOG.error(message); // ERROR (level 4+)
41+
}
42+
}
43+
44+
public HostFunction[] toHostFunctions() {
45+
return SharedCoreImports_ModuleFactory.toHostFunctions(this);
46+
}
47+
}

0 commit comments

Comments
 (0)