Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New interface refactor (sdk-api-kotlin) #238

Merged
merged 1 commit into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import net.ltgt.gradle.errorprone.errorprone

plugins {
java
kotlin("jvm") version "1.9.20" apply false
kotlin("plugin.serialization") version "1.9.20" apply false
kotlin("jvm") version "1.9.22" apply false
kotlin("plugin.serialization") version "1.9.22" apply false

id("net.ltgt.errorprone") version "3.0.1"
id("com.github.jk1.dependency-license-report") version "2.0"
Expand Down
4 changes: 2 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ For a sample project configuration and more elaborated examples, check out the [
Available examples:

* [`Counter`](src/main/java/my/restate/sdk/examples/Counter.java): Shows a simple virtual object using state primitives.
* [`CounterKt`](src/main/kotlin/dev/restate/sdk/examples/CounterKt.kt): Same as `Counter` but using Kotlin.
* [`Counter`](src/main/kotlin/my/restate/sdk/examples/Counter.kt): Same as `Counter` but using Kotlin.
* [`LoanWorkflow`](src/main/java/my/restate/sdk/examples/LoanWorkflow.java): Shows a simple workflow example using the Workflow API.

## Package the examples for Lambda
Expand Down Expand Up @@ -35,7 +35,7 @@ You can run the Java Counter example via:
You can modify the class to run setting `-PmainClass=<FQCN>`, for example, in order to run the Kotlin implementation:

```shell
./gradlew :examples:run -PmainClass=dev.restate.sdk.examples.CounterKt
./gradlew :examples:run -PmainClass=my.restate.sdk.examples.CounterKt
```

## Invoking the counter bindableComponent
Expand Down
7 changes: 5 additions & 2 deletions examples/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
java
// kotlin("jvm")
kotlin("jvm")
kotlin("plugin.serialization")
application
id("com.github.johnrengelman.shadow").version("7.1.2")
}
Expand All @@ -11,7 +12,7 @@ dependencies {
implementation(project(":sdk-api"))
implementation(project(":sdk-lambda"))
implementation(project(":sdk-http-vertx"))
// implementation(project(":sdk-api-kotlin"))
implementation(project(":sdk-api-kotlin"))
implementation(project(":sdk-serde-jackson"))
implementation(project(":sdk-workflow-api"))

Expand All @@ -26,6 +27,8 @@ dependencies {
implementation(vertxLibs.vertx.kotlin.coroutines)

implementation(kotlinLibs.kotlinx.coroutines)
implementation(kotlinLibs.kotlinx.serialization.core)
implementation(kotlinLibs.kotlinx.serialization.json)

implementation(coreLibs.log4j.core)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public void register(RestateLambdaEndpointBuilder builder) {
.split(Pattern.quote(","))) {
if (Counter.class.getCanonicalName().equals(serviceClass)) {
builder.with(new Counter());
// } else if (CounterKt.class.getCanonicalName().equals(serviceClass)) {
// builder.withService(new CounterKt());
} else if (CounterKt.class.getCanonicalName().equals(serviceClass)) {
builder.with(CounterKt.getCounter());
} else {
throw new IllegalArgumentException(
"Bad \"LAMBDA_FACTORY_SERVICE_CLASS\" env: " + serviceClass);
Expand Down
60 changes: 0 additions & 60 deletions examples/src/main/kotlin/dev/restate/sdk/examples/CounterKt.kt

This file was deleted.

40 changes: 40 additions & 0 deletions examples/src/main/kotlin/my/restate/sdk/examples/Counter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package my.restate.sdk.examples

import dev.restate.sdk.common.StateKey
import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder
import dev.restate.sdk.kotlin.Component
import dev.restate.sdk.kotlin.KtSerdes
import kotlinx.serialization.Serializable

@Serializable data class CounterUpdate(var oldValue: Long, val newValue: Long)

private val totalKey = StateKey.of<Long>("total", KtSerdes.json())

val counter =
Component.virtualObject("Counter") {
handler("reset") { ctx, _: Unit -> ctx.clear(totalKey) }
handler("add") { ctx, value: Long ->
val currentValue = ctx.get(totalKey) ?: 0L
val newValue = currentValue + value
ctx.set(totalKey, newValue)
}
handler("get") { ctx, _: Unit -> ctx.get(totalKey) ?: 0L }
handler("getAndAdd") { ctx, value: Long ->
val currentValue = ctx.get(totalKey) ?: 0L
val newValue = currentValue + value
ctx.set(totalKey, newValue)
CounterUpdate(currentValue, newValue)
}
}

fun main() {
RestateHttpEndpointBuilder.builder().with(counter).buildAndListen()
}
42 changes: 2 additions & 40 deletions sdk-api-kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import com.google.protobuf.gradle.id

plugins {
java
kotlin("jvm")
Expand All @@ -16,50 +14,14 @@ dependencies {
implementation(kotlinLibs.kotlinx.serialization.core)
implementation(kotlinLibs.kotlinx.serialization.json)

implementation(coreLibs.log4j.api)

testImplementation(project(":sdk-core"))
testImplementation(testingLibs.junit.jupiter)
testImplementation(testingLibs.assertj)
testImplementation(coreLibs.protobuf.java)
testImplementation(coreLibs.protobuf.kotlin)
testImplementation(coreLibs.grpc.stub)
testImplementation(coreLibs.grpc.protobuf)
testImplementation(coreLibs.grpc.kotlin.stub)
testImplementation(coreLibs.log4j.core)

testImplementation(project(":sdk-core", "testArchive"))
testProtobuf(project(":sdk-core", "testArchive"))
}

val pluginJar =
file(
"${project.rootProject.rootDir}/protoc-gen-restate/build/libs/protoc-gen-restate-${project.version}-all.jar")

protobuf {
plugins {
id("grpc") { artifact = "io.grpc:protoc-gen-grpc-java:${coreLibs.versions.grpc.get()}" }
id("grpckt") {
artifact = "io.grpc:protoc-gen-grpc-kotlin:${coreLibs.versions.grpckt.get()}:jdk8@jar"
}
id("restate") {
// NOTE: This is not needed in a regular project configuration, you should rather use:
// artifact = "dev.restate.sdk:protoc-gen-restate-java-blocking:1.0-SNAPSHOT:all@jar"
path = pluginJar.path
}
}

generateProtoTasks {
ofSourceSet("test").forEach {
// Make sure we depend on shadowJar from protoc-gen-restate
it.dependsOn(":protoc-gen-restate:shadowJar")

it.plugins {
id("grpc")
id("grpckt")
id("restate") { option("kotlin") }
}
it.builtins { id("kotlin") }
}
}
}

// Generate test jar
Expand Down
44 changes: 21 additions & 23 deletions sdk-api-kotlin/src/main/kotlin/dev/restate/sdk/kotlin/Awaitables.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,25 @@ internal abstract class BaseSingleMappedAwaitableImpl<T : Any, U : Any>(
}
}

// internal class SingleMappedAwaitableImpl<T: Any, U: Any>(inner: BaseAwaitableImpl<T>, private val
// mapper: suspend (res: Result<T>) -> Result<U>) : BaseSingleMappedAwaitableImpl<T, U>(inner) {
// override suspend fun map(res: Result<T>): Result<U> {
// return mapper(res)
// }
//
// }
internal open class SingleSerdeAwaitableImpl<T : Any>
internal constructor(
syscalls: Syscalls,
deferred: Deferred<ByteString>,
private val serde: Serde<T>,
) :
BaseSingleMappedAwaitableImpl<ByteString, T>(
SingleAwaitableImpl(syscalls, deferred),
) {
@Suppress("UNCHECKED_CAST")
override suspend fun map(res: Result<ByteString>): Result<T> {
return if (res.isSuccess) {
// This propagates exceptions as non-terminal
Result.success(serde.deserializeWrappingException(syscalls, res.value!!))
} else {
res as Result<T>
}
}
}

internal class UnitAwakeableImpl(syscalls: Syscalls, deferred: Deferred<Void>) :
BaseSingleMappedAwaitableImpl<Void, Unit>(SingleAwaitableImpl(syscalls, deferred)) {
Expand Down Expand Up @@ -140,23 +152,9 @@ internal class AwakeableImpl<T : Any>
internal constructor(
syscalls: Syscalls,
deferred: Deferred<ByteString>,
private val serde: Serde<T>,
serde: Serde<T>,
override val id: String
) :
BaseSingleMappedAwaitableImpl<ByteString, T>(
SingleAwaitableImpl(syscalls, deferred),
),
Awakeable<T> {

@Suppress("UNCHECKED_CAST")
override suspend fun map(res: Result<ByteString>): Result<T> {
return if (res.isSuccess) {
Result.success(serde.deserializeWrappingException(syscalls, res.value!!))
} else {
res as Result<T>
}
}
}
) : SingleSerdeAwaitableImpl<T>(syscalls, deferred, serde), Awakeable<T> {}

internal class AwakeableHandleImpl(val syscalls: Syscalls, val id: String) : AwakeableHandle {
override suspend fun <T : Any> resolve(serde: Serde<T>, payload: T) {
Expand Down
Loading
Loading