diff --git a/code_snippets/kotlin/build.gradle.kts b/code_snippets/kotlin/build.gradle.kts index 6c292846..a905297e 100644 --- a/code_snippets/kotlin/build.gradle.kts +++ b/code_snippets/kotlin/build.gradle.kts @@ -1,5 +1,3 @@ -import java.net.URI - plugins { application kotlin("jvm") version "2.0.0" @@ -10,9 +8,7 @@ plugins { id("com.diffplug.spotless") version "6.25.0" } -repositories { - mavenCentral() -} +repositories { mavenCentral() } val restateVersion = "1.0.1" @@ -32,22 +28,15 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") } -kotlin { - jvmToolchain(21) -} - +kotlin { jvmToolchain(21) } // Set main class -application { - mainClass.set("develop.Greeter") -} +application { mainClass.set("develop.Greeter") } spotless { - java { - googleJavaFormat() - importOrder() - removeUnusedImports() - formatAnnotations() - toggleOffOn("//", "/n") + kotlin { + targetExclude("build/generated/**/*.kt") + ktfmt() } -} \ No newline at end of file + kotlinGradle { ktfmt() } +} diff --git a/code_snippets/kotlin/settings.gradle.kts b/code_snippets/kotlin/settings.gradle.kts index 966445bb..a0be9017 100644 --- a/code_snippets/kotlin/settings.gradle.kts +++ b/code_snippets/kotlin/settings.gradle.kts @@ -1,3 +1 @@ -plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version("0.5.0") -} \ No newline at end of file +plugins { id("org.gradle.toolchains.foojay-resolver-convention") version ("0.5.0") } diff --git a/code_snippets/kotlin/src/main/kotlin/develop/Awakeables.kt b/code_snippets/kotlin/src/main/kotlin/develop/Awakeables.kt index f656d3c1..141fa045 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/Awakeables.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/Awakeables.kt @@ -3,34 +3,30 @@ package develop import dev.restate.sdk.kotlin.* class Awakeables { - suspend fun awakeables(ctx: ObjectContext) { - // - // - val awakeable = ctx.awakeable() - val awakeableId: String = awakeable.id - // - - // - ctx.runBlock{ triggerTaskAndDeliverId(awakeableId) } - // - - // - val payload: String = awakeable.await() - // - // - - - // - ctx.awakeableHandle(awakeableId) - .resolve("hello") - // - - // - ctx.awakeableHandle(awakeableId) - .reject("my error reason") - // - } - - private fun triggerTaskAndDeliverId(awakeableId: String): Unit { - } -} \ No newline at end of file + suspend fun awakeables(ctx: ObjectContext) { + // + // + val awakeable = ctx.awakeable() + val awakeableId: String = awakeable.id + // + + // + ctx.runBlock { triggerTaskAndDeliverId(awakeableId) } + // + + // + val payload: String = awakeable.await() + // + // + + // + ctx.awakeableHandle(awakeableId).resolve("hello") + // + + // + ctx.awakeableHandle(awakeableId).reject("my error reason") + // + } + + private fun triggerTaskAndDeliverId(awakeableId: String) {} +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/DurableTimers.kt b/code_snippets/kotlin/src/main/kotlin/develop/DurableTimers.kt index dbff211d..9784bf15 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/DurableTimers.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/DurableTimers.kt @@ -3,11 +3,10 @@ package develop import dev.restate.sdk.kotlin.Context import kotlin.time.Duration.Companion.seconds - class DurableTimers { - suspend fun timers(ctx: Context) { - // - ctx.sleep(10.seconds) - // - } -} \ No newline at end of file + suspend fun timers(ctx: Context) { + // + ctx.sleep(10.seconds) + // + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/ErrorHandling.kt b/code_snippets/kotlin/src/main/kotlin/develop/ErrorHandling.kt index fd33da87..9e0d0e09 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/ErrorHandling.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/ErrorHandling.kt @@ -4,11 +4,9 @@ import dev.restate.sdk.common.TerminalException import dev.restate.sdk.kotlin.Context class ErrorHandling { - fun errorHandling(ctx: Context) { - - // - throw TerminalException(500, "Something went wrong") - // - - } + fun errorHandling(ctx: Context) { + // + throw TerminalException(500, "Something went wrong") + // + } } diff --git a/code_snippets/kotlin/src/main/kotlin/develop/Greeter.kt b/code_snippets/kotlin/src/main/kotlin/develop/Greeter.kt index 80ce832f..779d3bf2 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/Greeter.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/Greeter.kt @@ -1,33 +1,32 @@ package develop -import dev.restate.sdk.annotation.* +import dev.restate.sdk.annotation.Handler +import dev.restate.sdk.annotation.VirtualObject import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder -import dev.restate.sdk.kotlin.* +import dev.restate.sdk.kotlin.KtStateKey +import dev.restate.sdk.kotlin.ObjectContext // withClass tooltip java-overview-virtual-object @VirtualObject class Greeter { - // withClass(1:3) tooltip java-overview-state-key - companion object { - private val COUNT = KtStateKey.json("count") - } + // withClass(1:3) tooltip java-overview-state-key + companion object { + private val COUNT = KtStateKey.json("count") + } - // withClass tooltip java-overview-virtual-object-handler - @Handler - suspend fun greet(ctx: ObjectContext, greeting: String): String { - // Get the count and increment it - val count = ctx.get(COUNT) ?: 1 - ctx.set(COUNT, count + 1) + // withClass tooltip java-overview-virtual-object-handler + @Handler + suspend fun greet(ctx: ObjectContext, greeting: String): String { + // Get the count and increment it + val count = ctx.get(COUNT) ?: 1 + ctx.set(COUNT, count + 1) - // Send the response back - return "$greeting ${ctx.key()} for the $count time!" - } + // Send the response back + return "$greeting ${ctx.key()} for the $count time!" + } } fun main() { - RestateHttpEndpointBuilder - .builder() - .bind(Greeter()) - .buildAndListen() + RestateHttpEndpointBuilder.builder().bind(Greeter()).buildAndListen() } diff --git a/code_snippets/kotlin/src/main/kotlin/develop/JournalingResults.kt b/code_snippets/kotlin/src/main/kotlin/develop/JournalingResults.kt index 85729db2..91d4ee16 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/JournalingResults.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/JournalingResults.kt @@ -2,83 +2,81 @@ package develop import dev.restate.sdk.common.TerminalException import dev.restate.sdk.kotlin.* -import java.util.* +import java.util.UUID internal class SideEffects { - suspend fun sideEffect(ctx: Context) { - // - val output: String = ctx.runBlock { doDbRequest() } - // + suspend fun sideEffect(ctx: Context) { + // + val output: String = ctx.runBlock { doDbRequest() } + // - val paymentClient = PaymentClient() - val txId = "" - val amount = 1 - - // - ctx.runBlock { - val result = paymentClient.call(txId, amount) - if (result) { - // withClass highlight-line - throw IllegalStateException("Payment failed") - } else { - result - } - } - // + val paymentClient = PaymentClient() + val txId = "" + val amount = 1 + // + ctx.runBlock { + val result = paymentClient.call(txId, amount) + if (result) { + // withClass highlight-line + throw IllegalStateException("Payment failed") + } else { + result + } + } + // - // - try { - ctx.runBlock { - val result = paymentClient.call(txId, amount) - if (result) { - // withClass highlight-line - throw TerminalException(TerminalException.INTERNAL_SERVER_ERROR_CODE, "Payment failed") - } else { - result - } - } - } catch (e: TerminalException) { - // handle terminal error + // + try { + ctx.runBlock { + val result = paymentClient.call(txId, amount) + if (result) { + // withClass highlight-line + throw TerminalException(TerminalException.INTERNAL_SERVER_ERROR_CODE, "Payment failed") + } else { + result } - // + } + } catch (e: TerminalException) { + // handle terminal error + } + // - val a1 = ctx.awakeable() - val a2 = ctx.awakeable() - val a3 = ctx.awakeable() + val a1 = ctx.awakeable() + val a2 = ctx.awakeable() + val a3 = ctx.awakeable() - // - listOf(a1, a2, a3).awaitAll() - // + // + listOf(a1, a2, a3).awaitAll() + // - // - val res = Awaitable.any(a1, a2, a3) - .await() as Boolean + // + val res = Awaitable.any(a1, a2, a3).await() as Boolean - // Or using the select statement - val resSelect = select { - a1.onAwait { it } - a2.onAwait { it } - a3.onAwait { it } - } - // + // Or using the select statement + val resSelect = select { + a1.onAwait { it } + a2.onAwait { it } + a3.onAwait { it } + } + // - // - val uuid: UUID = ctx.random().nextUUID() - // + // + val uuid: UUID = ctx.random().nextUUID() + // - // - val value: Int = ctx.random().nextInt() - // - } + // + val value: Int = ctx.random().nextInt() + // + } - private fun doDbRequest(): String { - return "" - } + private fun doDbRequest(): String { + return "" + } } internal class PaymentClient { - fun call(txId: String?, amount: Int): Boolean { - return true - } -} \ No newline at end of file + fun call(txId: String?, amount: Int): Boolean { + return true + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/MyLambdaHandler.kt b/code_snippets/kotlin/src/main/kotlin/develop/MyLambdaHandler.kt index 54e3f225..a1f4ef23 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/MyLambdaHandler.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/MyLambdaHandler.kt @@ -5,10 +5,8 @@ import dev.restate.sdk.lambda.BaseRestateLambdaHandler import dev.restate.sdk.lambda.RestateLambdaEndpointBuilder class MyLambdaHandler : BaseRestateLambdaHandler() { - override fun register(builder: RestateLambdaEndpointBuilder) { - builder - .bind(MyService()) - .bind(MyVirtualObject()) - } + override fun register(builder: RestateLambdaEndpointBuilder) { + builder.bind(MyService()).bind(MyVirtualObject()) + } } // diff --git a/code_snippets/kotlin/src/main/kotlin/develop/MyService.kt b/code_snippets/kotlin/src/main/kotlin/develop/MyService.kt index 891ea7fa..2c4f538c 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/MyService.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/MyService.kt @@ -8,16 +8,13 @@ import dev.restate.sdk.kotlin.Context // @Service class MyService { - @Handler - suspend fun myHandler(ctx: Context, input: String): String { - return "my-output" - } + @Handler + suspend fun myHandler(ctx: Context, input: String): String { + return "my-output" + } } fun main() { - RestateHttpEndpointBuilder - .builder() - .bind(MyService()) - .buildAndListen() + RestateHttpEndpointBuilder.builder().bind(MyService()).buildAndListen() } // diff --git a/code_snippets/kotlin/src/main/kotlin/develop/MyVirtualObject.kt b/code_snippets/kotlin/src/main/kotlin/develop/MyVirtualObject.kt index fa242371..b8e65fd5 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/MyVirtualObject.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/MyVirtualObject.kt @@ -11,22 +11,18 @@ import dev.restate.sdk.kotlin.SharedObjectContext @VirtualObject class MyVirtualObject { - @Handler - suspend fun myHandler(ctx: ObjectContext, input: String): String { - return "my-output" - } + @Handler + suspend fun myHandler(ctx: ObjectContext, input: String): String { + return "my-output" + } - - @Shared - suspend fun myConcurrentHandler(ctx: SharedObjectContext, input: String): String { - return "my-output" - } + @Shared + suspend fun myConcurrentHandler(ctx: SharedObjectContext, input: String): String { + return "my-output" + } } fun main() { - RestateHttpEndpointBuilder - .builder() - .bind(MyVirtualObject()) - .buildAndListen() + RestateHttpEndpointBuilder.builder().bind(MyVirtualObject()).buildAndListen() } // diff --git a/code_snippets/kotlin/src/main/kotlin/develop/MyWorkflow.kt b/code_snippets/kotlin/src/main/kotlin/develop/MyWorkflow.kt index c8bd8b4d..2106c208 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/MyWorkflow.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/MyWorkflow.kt @@ -5,31 +5,25 @@ import dev.restate.sdk.annotation.Workflow import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder import dev.restate.sdk.kotlin.SharedWorkflowContext import dev.restate.sdk.kotlin.WorkflowContext -import kotlin.time.Duration // @Workflow class MyWorkflow { - @Workflow - suspend fun run(ctx: WorkflowContext, input: String): String { + @Workflow + suspend fun run(ctx: WorkflowContext, input: String): String { + // implement workflow logic here - // implement workflow logic here - - return "success" - } - - @Handler - suspend fun interactWithWorkflow(ctx: SharedWorkflowContext, input: String) { - // implement interaction logic here - } + return "success" + } + @Handler + suspend fun interactWithWorkflow(ctx: SharedWorkflowContext, input: String) { + // implement interaction logic here + } } fun main() { - RestateHttpEndpointBuilder - .builder() - .bind(MyWorkflow()) - .buildAndListen() + RestateHttpEndpointBuilder.builder().bind(MyWorkflow()).buildAndListen() } // diff --git a/code_snippets/kotlin/src/main/kotlin/develop/SerializationExample.kt b/code_snippets/kotlin/src/main/kotlin/develop/SerializationExample.kt index ae8d6f18..ff4dbc99 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/SerializationExample.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/SerializationExample.kt @@ -3,12 +3,12 @@ package develop import dev.restate.sdk.kotlin.KtSerdes class SerializationExample { - data class MyDataClass(val a: Int) + data class MyDataClass(val a: Int) - // - private fun someFn() { - // - KtSerdes.json() - // - } -} \ No newline at end of file + // + private fun someFn() { + // + KtSerdes.json() + // + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/ServiceCommunication.kt b/code_snippets/kotlin/src/main/kotlin/develop/ServiceCommunication.kt index 8b1d086f..4d66f2d4 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/ServiceCommunication.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/ServiceCommunication.kt @@ -4,63 +4,56 @@ import dev.restate.sdk.kotlin.Context import kotlin.time.Duration.Companion.seconds class ServiceCommunication { - suspend fun requestResponseService(ctx: Context) { - val request = "" - - // - val response: String = MyServiceClient.fromContext(ctx) - .myHandler(request) - .await() - // - } - - suspend fun requestResponseVirtualObject(ctx: Context) { - val objectKey = "" - val request = "" - - // - val response: String = MyVirtualObjectClient.fromContext(ctx, objectKey) - .myHandler(request) - .await() - // - } - - suspend fun requestResponseWorkflow(ctx: Context) { - val workflowId = "" - val request = "" - - // - // Call the `run` handler of the workflow - val response: String = MyWorkflowClient.fromContext(ctx, workflowId) - .run(request) - .await() - - // Call some other `interactWithWorkflow` handler of the workflow. - MyWorkflowClient.fromContext(ctx, workflowId) - .interactWithWorkflow(request) - .await() - // - } - - suspend fun oneWay(ctx: Context) { - val request = "" - - // - MyServiceClient.fromContext(ctx) - // withClass highlight-line - .send() - .myHandler(request) - // - } - - suspend fun delayedCall(ctx: Context) { - val request = "" - - // - MyServiceClient.fromContext(ctx) - // withClass highlight-line - .send(1.seconds) - .myHandler(request) - // - } + suspend fun requestResponseService(ctx: Context) { + val request = "" + + // + val response: String = MyServiceClient.fromContext(ctx).myHandler(request).await() + // + } + + suspend fun requestResponseVirtualObject(ctx: Context) { + val objectKey = "" + val request = "" + + // + val response: String = + MyVirtualObjectClient.fromContext(ctx, objectKey).myHandler(request).await() + // + } + + suspend fun requestResponseWorkflow(ctx: Context) { + val workflowId = "" + val request = "" + + // + // Call the `run` handler of the workflow + val response: String = MyWorkflowClient.fromContext(ctx, workflowId).run(request).await() + + // Call some other `interactWithWorkflow` handler of the workflow. + MyWorkflowClient.fromContext(ctx, workflowId).interactWithWorkflow(request).await() + // + } + + suspend fun oneWay(ctx: Context) { + val request = "" + + // + MyServiceClient.fromContext(ctx) + // withClass highlight-line + .send() + .myHandler(request) + // + } + + suspend fun delayedCall(ctx: Context) { + val request = "" + + // + MyServiceClient.fromContext(ctx) + // withClass highlight-line + .send(1.seconds) + .myHandler(request) + // + } } diff --git a/code_snippets/kotlin/src/main/kotlin/develop/ServingHttp.kt b/code_snippets/kotlin/src/main/kotlin/develop/ServingHttp.kt index 8cd77cf0..2cfddf3e 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/ServingHttp.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/ServingHttp.kt @@ -4,11 +4,10 @@ package develop import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder fun main() { - RestateHttpEndpointBuilder.builder() - .bind(MyService()) - .bind(MyVirtualObject()) - .bind(MyWorkflow()) - .buildAndListen() + RestateHttpEndpointBuilder.builder() + .bind(MyService()) + .bind(MyVirtualObject()) + .bind(MyWorkflow()) + .buildAndListen() } // - diff --git a/code_snippets/kotlin/src/main/kotlin/develop/ServingIdentity.kt b/code_snippets/kotlin/src/main/kotlin/develop/ServingIdentity.kt index 4b4c2026..35e52922 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/ServingIdentity.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/ServingIdentity.kt @@ -5,15 +5,15 @@ import dev.restate.sdk.auth.signing.RestateRequestIdentityVerifier import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder fun main() { - RestateHttpEndpointBuilder.builder() - .bind(MyService()) - .bind(MyVirtualObject()) - .bind(MyWorkflow()) - .withRequestIdentityVerifier( - RestateRequestIdentityVerifier.fromKeys( - "publickeyv1_w7YHemBctH5Ck2nQRQ47iBBqhNHy4FV7t2Usbye2A6f" - ) - ) - .buildAndListen() + RestateHttpEndpointBuilder.builder() + .bind(MyService()) + .bind(MyVirtualObject()) + .bind(MyWorkflow()) + .withRequestIdentityVerifier( + RestateRequestIdentityVerifier.fromKeys( + "publickeyv1_w7YHemBctH5Ck2nQRQ47iBBqhNHy4FV7t2Usbye2A6f", + ), + ) + .buildAndListen() } // diff --git a/code_snippets/kotlin/src/main/kotlin/develop/ServingVirtualThreads.kt b/code_snippets/kotlin/src/main/kotlin/develop/ServingVirtualThreads.kt index 291cd891..28964e24 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/ServingVirtualThreads.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/ServingVirtualThreads.kt @@ -6,15 +6,15 @@ import java.util.concurrent.Executors import kotlinx.coroutines.asCoroutineDispatcher class ServingVirtualThreads { - fun virtualThreads(builder: RestateHttpEndpointBuilder) { - // - builder.bind( - // This is the class generated by the annotation processor - GreeterServiceDefinitionFactory().create(Greeter()), - HandlerRunner.Options( - coroutineContext = Executors.newVirtualThreadPerTaskExecutor().asCoroutineDispatcher() - ) - ) - // - } + fun virtualThreads(builder: RestateHttpEndpointBuilder) { + // + builder.bind( + // This is the class generated by the annotation processor + GreeterServiceDefinitionFactory().create(Greeter()), + HandlerRunner.Options( + coroutineContext = Executors.newVirtualThreadPerTaskExecutor().asCoroutineDispatcher(), + ), + ) + // + } } diff --git a/code_snippets/kotlin/src/main/kotlin/develop/State.kt b/code_snippets/kotlin/src/main/kotlin/develop/State.kt index 0bec2066..f2504baa 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/State.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/State.kt @@ -1,42 +1,43 @@ +// Suppressing notifications about the naming of the state keys: not lower case +@file:Suppress("ktlint:standard:property-naming") + package develop import dev.restate.sdk.kotlin.KtStateKey import dev.restate.sdk.kotlin.ObjectContext class State { - suspend fun getState(ctx: ObjectContext) { - // - val keys = ctx.stateKeys() - // - - - // - // Getting String value - val STRING_STATE_KEY = KtStateKey.json("my-key") - val stringState: String? = ctx.get(STRING_STATE_KEY) - - // Getting integer value - val INT_STATE_KEY = KtStateKey.json("my-key") - val intState: Int? = ctx.get(INT_STATE_KEY) - // - } - suspend fun setState(ctx: ObjectContext) { - - // - val STRING_STATE_KEY = KtStateKey.json("my-key") - ctx.set(STRING_STATE_KEY, "my-new-value") - // - - - } - suspend fun clearState(ctx: ObjectContext) { - // - val STRING_STATE_KEY = KtStateKey.json("my-key") - ctx.clear(STRING_STATE_KEY) - // - - // - ctx.clearAll() - // - } -} \ No newline at end of file + suspend fun getState(ctx: ObjectContext) { + // + val keys = ctx.stateKeys() + // + + // + // Getting String value + val STRING_STATE_KEY = KtStateKey.json("my-key") + val stringState: String? = ctx.get(STRING_STATE_KEY) + + // Getting integer value + val INT_STATE_KEY = KtStateKey.json("my-key") + val intState: Int? = ctx.get(INT_STATE_KEY) + // + } + + suspend fun setState(ctx: ObjectContext) { + // + val STRING_STATE_KEY = KtStateKey.json("my-key") + ctx.set(STRING_STATE_KEY, "my-new-value") + // + } + + suspend fun clearState(ctx: ObjectContext) { + // + val STRING_STATE_KEY = KtStateKey.json("my-key") + ctx.clear(STRING_STATE_KEY) + // + + // + ctx.clearAll() + // + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/clients/GreetCounterObject.kt b/code_snippets/kotlin/src/main/kotlin/develop/clients/GreetCounterObject.kt index 8c98277f..ef414322 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/clients/GreetCounterObject.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/clients/GreetCounterObject.kt @@ -5,29 +5,27 @@ import dev.restate.sdk.annotation.VirtualObject import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder import dev.restate.sdk.kotlin.KtStateKey import dev.restate.sdk.kotlin.ObjectContext -import develop.workflows.SignupWorkflow @VirtualObject class GreetCounterObject { - companion object { - private val COUNT = KtStateKey.json("count") - } + companion object { + private val COUNT = KtStateKey.json("count") + } - @Handler - suspend fun greet(ctx: ObjectContext, greeting: String): Int { - val count = ctx.get(COUNT) ?: 0 + @Handler + suspend fun greet(ctx: ObjectContext, greeting: String): Int { + val count = ctx.get(COUNT) ?: 0 - val newCount = count + 1 - ctx.set(COUNT, newCount) - return newCount - } + val newCount = count + 1 + ctx.set(COUNT, newCount) + return newCount + } } fun main() { - RestateHttpEndpointBuilder - .builder() - .bind(GreetCounterObject()) - .bind(GreeterService()) - .buildAndListen() -} \ No newline at end of file + RestateHttpEndpointBuilder.builder() + .bind(GreetCounterObject()) + .bind(GreeterService()) + .buildAndListen() +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/clients/GreeterService.kt b/code_snippets/kotlin/src/main/kotlin/develop/clients/GreeterService.kt index 978712b5..2c2a0311 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/clients/GreeterService.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/clients/GreeterService.kt @@ -6,9 +6,8 @@ import dev.restate.sdk.kotlin.Context @Service class GreeterService { - @Handler - suspend fun greet(ctx: Context, greeting: String): String { - return "Hello, $greeting!" - } + @Handler + suspend fun greet(ctx: Context, greeting: String): String { + return "Hello, $greeting!" + } } - diff --git a/code_snippets/kotlin/src/main/kotlin/develop/clients/Ingress.kt b/code_snippets/kotlin/src/main/kotlin/develop/clients/Ingress.kt index 18facc10..d2d3f5fe 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/clients/Ingress.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/clients/Ingress.kt @@ -4,7 +4,6 @@ import dev.restate.sdk.client.CallRequestOptions import dev.restate.sdk.client.Client import dev.restate.sdk.client.SendResponse import dev.restate.sdk.common.Output -import dev.restate.sdk.kotlin.Context import dev.restate.sdk.kotlin.KtSerdes import develop.clients.GreetCounterObjectClient import develop.clients.GreeterServiceClient @@ -12,81 +11,78 @@ import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds class Ingress { - suspend fun myJavaHandler() { - // - val rs = Client.connect("http://localhost:8080") - val greet: String = GreeterServiceClient.fromClient(rs) - .greet("Hi") + suspend fun myJavaHandler() { + // + val rs = Client.connect("http://localhost:8080") + val greet: String = GreeterServiceClient.fromClient(rs).greet("Hi") - val count: Int = GreetCounterObjectClient.fromClient(rs, "Mary") - .greet("Hi") - // - } + val count: Int = GreetCounterObjectClient.fromClient(rs, "Mary").greet("Hi") + // + } - suspend fun myOneWayCallHandler() { - // - val rs = Client.connect("http://localhost:8080") - GreeterServiceClient.fromClient(rs) - // mark - .send() - .greet("Hi") + suspend fun myOneWayCallHandler() { + // + val rs = Client.connect("http://localhost:8080") + GreeterServiceClient.fromClient(rs) + // mark + .send() + .greet("Hi") - GreetCounterObjectClient.fromClient(rs, "Mary") - // mark - .send() - .greet("Hi") - // - } + GreetCounterObjectClient.fromClient(rs, "Mary") + // mark + .send() + .greet("Hi") + // + } - suspend fun myDelayedOneWayCallHandler() { - // - val rs = Client.connect("http://localhost:8080") - GreeterServiceClient.fromClient(rs) - // withClass highlight-line - .send(1.seconds) - .greet("Hi") + suspend fun myDelayedOneWayCallHandler() { + // + val rs = Client.connect("http://localhost:8080") + GreeterServiceClient.fromClient(rs) + // withClass highlight-line + .send(1.seconds) + .greet("Hi") - GreetCounterObjectClient.fromClient(rs, "Mary") - // withClass highlight-line - .send(1000.milliseconds) - .greet("Hi") - // - } + GreetCounterObjectClient.fromClient(rs, "Mary") + // withClass highlight-line + .send(1000.milliseconds) + .greet("Hi") + // + } - suspend fun idempotentInvoke() { - // - val rs = Client.connect("http://localhost:8080") - GreetCounterObjectClient.fromClient(rs, "Mary") - .send() - // withClass highlight-line - .greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde")) - // - } + suspend fun idempotentInvoke() { + // + val rs = Client.connect("http://localhost:8080") + GreetCounterObjectClient.fromClient(rs, "Mary") + .send() + // withClass highlight-line + .greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde")) + // + } - suspend fun attach() { - // - val rs = Client.connect("http://localhost:8080") - val handle: SendResponse = GreeterServiceClient.fromClient(rs) + suspend fun attach() { + // + val rs = Client.connect("http://localhost:8080") + val handle: SendResponse = + GreeterServiceClient.fromClient(rs) .send() // mark .greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde")) - // ... do something else ... + // ... do something else ... - // Option 1: Attach later to retrieve the result - // mark(1:3) - val greeting: String = rs - .invocationHandle(handle.invocationId, KtSerdes.json()) - .attach() + // Option 1: Attach later to retrieve the result + // mark(1:3) + val greeting: String = + rs.invocationHandle(handle.invocationId, KtSerdes.json()).attach() - // Option 2: Peek to see if the result is ready - // mark(1:3) - val output: Output = rs - .invocationHandle(handle.invocationId, KtSerdes.json()) - .output - if (output.isReady) { - val result = output.value - } - // + // Option 2: Peek to see if the result is ready + // mark(1:3) + val output: Output = + rs.invocationHandle(handle.invocationId, KtSerdes.json()).output + if (output.isReady) { + val result = output.value } -} \ No newline at end of file + // + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/workflows/SignupWorkflow.kt b/code_snippets/kotlin/src/main/kotlin/develop/workflows/SignupWorkflow.kt index 66851e47..8677b499 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/workflows/SignupWorkflow.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/workflows/SignupWorkflow.kt @@ -10,59 +10,50 @@ import kotlinx.serialization.Serializable @Workflow class SignupWorkflow { - companion object { - private val EMAIL_CLICKED = KtDurablePromiseKey.json("email_clicked") - private val STATUS = KtStateKey.json("status") - } - - // - @Workflow - suspend fun run(ctx: WorkflowContext, email: Email): Boolean { - val secret = ctx.random().nextUUID().toString() - ctx.set(STATUS, "Generated secret") - - ctx.runBlock ("send email") { - sendEmailWithLink(email, secret) - } - - // - val clickSecret = ctx.promise(EMAIL_CLICKED) - .awaitable() - .await() - // - ctx.set(STATUS, "Clicked email") - - return clickSecret == secret - } - // - - @Shared - suspend fun click(ctx: SharedWorkflowContext, secret: String) { - // - ctx.promiseHandle(EMAIL_CLICKED).resolve(secret) - // - } - - // - @Shared - suspend fun getStatus(ctx: SharedWorkflowContext): String? { - return ctx.get(STATUS) - } - // + companion object { + private val EMAIL_CLICKED = KtDurablePromiseKey.json("email_clicked") + private val STATUS = KtStateKey.json("status") + } + + // + @Workflow + suspend fun run(ctx: WorkflowContext, email: Email): Boolean { + val secret = ctx.random().nextUUID().toString() + ctx.set(STATUS, "Generated secret") + + ctx.runBlock("send email") { sendEmailWithLink(email, secret) } + + // + val clickSecret = ctx.promise(EMAIL_CLICKED).awaitable().await() + // + ctx.set(STATUS, "Clicked email") + + return clickSecret == secret + } + // + + @Shared + suspend fun click(ctx: SharedWorkflowContext, secret: String) { + // + ctx.promiseHandle(EMAIL_CLICKED).resolve(secret) + // + } + + // + @Shared + suspend fun getStatus(ctx: SharedWorkflowContext): String? { + return ctx.get(STATUS) + } + // } - fun main() { - // - RestateHttpEndpointBuilder - .builder() - .bind(SignupWorkflow()) - .buildAndListen() - // + // + RestateHttpEndpointBuilder.builder().bind(SignupWorkflow()).buildAndListen() + // } // -@Serializable -data class Email(val email: String) +@Serializable data class Email(val email: String) -fun sendEmailWithLink(email: Email, secret: String){} \ No newline at end of file +fun sendEmailWithLink(email: Email, secret: String) {} diff --git a/code_snippets/kotlin/src/main/kotlin/develop/workflows/UserManagementService.kt b/code_snippets/kotlin/src/main/kotlin/develop/workflows/UserManagementService.kt index c0e6780d..db6703e3 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/workflows/UserManagementService.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/workflows/UserManagementService.kt @@ -1,27 +1,22 @@ package develop.workflows -import dev.restate.sdk.annotation.Handler; -import dev.restate.sdk.annotation.VirtualObject; +import dev.restate.sdk.annotation.Handler +import dev.restate.sdk.annotation.VirtualObject import dev.restate.sdk.kotlin.ObjectContext @VirtualObject class UserManagementService { - // - @Handler - suspend fun setup(ctx: ObjectContext, email: Email) { - // focus(1:3) - val result = SignupWorkflowClient.fromContext(ctx, "someone") - .run(email) - .await() + // + @Handler + suspend fun setup(ctx: ObjectContext, email: Email) { + // focus(1:3) + val result = SignupWorkflowClient.fromContext(ctx, "someone").run(email).await() + } - } - - @Handler - suspend fun queryStatus(ctx: ObjectContext) { - // focus(1:3) - val status = SignupWorkflowClient.fromContext(ctx, "someone") - .getStatus() - .await() - } - // + @Handler + suspend fun queryStatus(ctx: ObjectContext) { + // focus(1:3) + val status = SignupWorkflowClient.fromContext(ctx, "someone").getStatus().await() + } + // } diff --git a/code_snippets/kotlin/src/main/kotlin/develop/workflows/WorkflowSubmitter.kt b/code_snippets/kotlin/src/main/kotlin/develop/workflows/WorkflowSubmitter.kt index 7f4ecd2f..2cd8c8f3 100644 --- a/code_snippets/kotlin/src/main/kotlin/develop/workflows/WorkflowSubmitter.kt +++ b/code_snippets/kotlin/src/main/kotlin/develop/workflows/WorkflowSubmitter.kt @@ -5,39 +5,29 @@ import dev.restate.sdk.client.SendResponse class WorkflowSubmitter { - suspend fun submitWorkflow(email: Email){ - // - val restate = Client.connect("http://localhost:8080") - val handle: SendResponse = SignupWorkflowClient - .fromClient(restate, "someone") - .submit(email) - // - - // - val status = SignupWorkflowClient - .fromClient(restate, "someone") - .getStatus() - // - - // - - // - - // - // Option 1: attach and wait for result - val result = SignupWorkflowClient - .fromClient(restate, "someone") - .workflowHandle() - .attach() - - // Option 2: peek to check if ready - val peekOutput = SignupWorkflowClient - .fromClient(restate, "someone") - .workflowHandle() - .output - if (peekOutput.isReady) { - val result2 = peekOutput.value - } - // + suspend fun submitWorkflow(email: Email) { + // + val restate = Client.connect("http://localhost:8080") + val handle: SendResponse = SignupWorkflowClient.fromClient(restate, "someone").submit(email) + // + + // + val status = SignupWorkflowClient.fromClient(restate, "someone").getStatus() + // + + // + + // + + // + // Option 1: attach and wait for result + val result = SignupWorkflowClient.fromClient(restate, "someone").workflowHandle().attach() + + // Option 2: peek to check if ready + val peekOutput = SignupWorkflowClient.fromClient(restate, "someone").workflowHandle().output + if (peekOutput.isReady) { + val result2 = peekOutput.value } -} \ No newline at end of file + // + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/FanOutWorker.kt b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/FanOutWorker.kt index d65c238b..decff32a 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/FanOutWorker.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/FanOutWorker.kt @@ -2,49 +2,54 @@ package usecases.asynctasks import dev.restate.sdk.annotation.Handler import dev.restate.sdk.annotation.Service -import dev.restate.sdk.kotlin.* +import dev.restate.sdk.kotlin.Awaitable +import dev.restate.sdk.kotlin.Context +import dev.restate.sdk.kotlin.awaitAll +import dev.restate.sdk.kotlin.runBlock // @Service class FanOutWorker { - @Handler - suspend fun run(ctx: Context, task: Task): Result { - val subTasks = ctx.runBlock { split(task) } - - val resultFutures: MutableList> = mutableListOf() - // - for (subTask in subTasks) { - val subResultFuture = FanOutWorkerClient.fromContext(ctx) - .runSubtask(subTask) - - // - resultFutures.add(subResultFuture) - } - - // - val results = resultFutures.awaitAll() - // - return aggregate(results) - } + @Handler + suspend fun run(ctx: Context, task: Task): Result { + val subTasks = ctx.runBlock { split(task) } + + val resultFutures: MutableList> = mutableListOf() + // + for (subTask in subTasks) { + val subResultFuture = FanOutWorkerClient.fromContext(ctx).runSubtask(subTask) - @Handler - suspend fun runSubtask(ctx: Context?, subTask: SubTask?): SubTaskResult { - // Processing logic goes here ... - // Can be moved to a separate service to scale independently - return SubTaskResult() + // + resultFutures.add(subResultFuture) } + + // + val results = resultFutures.awaitAll() + // + return aggregate(results) + } + + @Handler + suspend fun runSubtask(ctx: Context?, subTask: SubTask?): SubTaskResult { + // Processing logic goes here ... + // Can be moved to a separate service to scale independently + return SubTaskResult() + } } // class Result + class SubTask + class Task + class SubTaskResult fun split(task: Task): Array { - return emptyArray() + return emptyArray() } fun aggregate(subResults: List): Result { - return Result() -} \ No newline at end of file + return Result() +} diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/AsyncTaskService.kt b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/AsyncTaskService.kt index 2ccc7148..beff24e8 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/AsyncTaskService.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/AsyncTaskService.kt @@ -7,17 +7,17 @@ import dev.restate.sdk.kotlin.Context // @Service class AsyncTaskService { - // - @Handler - suspend fun runTask(ctx: Context, params: TaskOpts): String { - return someHeavyWork(params) - } -// + // + @Handler + suspend fun runTask(ctx: Context, params: TaskOpts): String { + return someHeavyWork(params) + } + // } // -class TaskOpts{} +class TaskOpts fun someHeavyWork(task: TaskOpts): String { - return "" -} \ No newline at end of file + return "" +} diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/TaskSubmitter.kt b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/TaskSubmitter.kt index b9a4eb86..711726ae 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/TaskSubmitter.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/simple/TaskSubmitter.kt @@ -6,30 +6,32 @@ import dev.restate.sdk.kotlin.KtSerdes // class TaskSubmitter { - companion object { - private val rs: Client = Client.connect("http://localhost:8080") - } + companion object { + private val rs: Client = Client.connect("http://localhost:8080") + } - suspend fun submitAndAwaitTasks(taskOpts: TaskOpts) { - // - val handle = AsyncTaskServiceClient.fromClient(rs) - .send() - .runTask( - taskOpts, - // - CallRequestOptions.DEFAULT.withIdempotency("dQw4w9WgXcQ") - // - ) - // + suspend fun submitAndAwaitTasks(taskOpts: TaskOpts) { + // + val handle = + AsyncTaskServiceClient.fromClient(rs) + .send() + .runTask( + taskOpts, + // + CallRequestOptions.DEFAULT.withIdempotency("dQw4w9WgXcQ"), + // + ) + // - // await the handler's result - // - val result = rs.invocationHandle( + // await the handler's result + // + val result = + rs.invocationHandle( handle.invocationId, - KtSerdes.json() + KtSerdes.json(), ) .attach() - // - } + // + } } -// \ No newline at end of file +// diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/DataPreparationService.kt b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/DataPreparationService.kt index 8efa85be..c9f8d6ac 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/DataPreparationService.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/DataPreparationService.kt @@ -13,34 +13,33 @@ import develop.workflows.Email @Workflow class DataPreparationService { - companion object { - private val URL_PROMISE = DurablePromiseKey.of("url", KtSerdes.json()) - } - - @Workflow - suspend fun run(ctx: WorkflowContext, userId: String): URL { - val url: URL = ctx.runBlock { createS3Bucket() } - ctx.runBlock { uploadData(url) } - - ctx.promiseHandle(URL_PROMISE).resolve(url) - return url - } - - @Shared - suspend fun resultAsEmail(ctx: SharedWorkflowContext, email: Email) { - val url: URL = ctx.promise(URL_PROMISE).awaitable().await() - ctx.runBlock { sendEmail(url, email) } - } + companion object { + private val URL_PROMISE = DurablePromiseKey.of("url", KtSerdes.json()) + } + + @Workflow + suspend fun run(ctx: WorkflowContext, userId: String): URL { + val url: URL = ctx.runBlock { createS3Bucket() } + ctx.runBlock { uploadData(url) } + + ctx.promiseHandle(URL_PROMISE).resolve(url) + return url + } + + @Shared + suspend fun resultAsEmail(ctx: SharedWorkflowContext, email: Email) { + val url: URL = ctx.promise(URL_PROMISE).awaitable().await() + ctx.runBlock { sendEmail(url, email) } + } } // -class URL{} +class URL fun createS3Bucket(): URL { - return URL() + return URL() } -fun uploadData(url: URL){} +fun uploadData(url: URL) {} fun sendEmail(url: URL, email: Email) {} - diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/MyClient.kt b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/MyClient.kt index 9e4cc624..ff8f0dee 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/MyClient.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/asynctasks/synctoasync/MyClient.kt @@ -2,41 +2,35 @@ package usecases.asynctasks.synctoasync import dev.restate.sdk.client.Client import develop.workflows.Email -import usecases.asynctasks.synctoasync.DataPreparationServiceClient.IngressClient -import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit -import kotlin.time.Duration.Companion.seconds // class MyClient { - companion object { - private val rs: Client = Client.connect("http://localhost:8080") - } + companion object { + private val rs: Client = Client.connect("http://localhost:8080") + } - suspend fun downloadData(userId: String, email: Email) { - // - val client = DataPreparationServiceClient.fromClient(rs, userId) - // + suspend fun downloadData(userId: String, email: Email) { + // + val client = DataPreparationServiceClient.fromClient(rs, userId) + // - // - client.submit(userId) - // + // + client.submit(userId) + // - try { - // - client.workflowHandle() - .attachAsync() - .orTimeout(30, TimeUnit.SECONDS) - .join() - // - // - } catch (e: Exception) { - client.resultAsEmail(email) - return - } - // - // ... process directly ... + try { + // + client.workflowHandle().attachAsync().orTimeout(30, TimeUnit.SECONDS).join() + // + // + } catch (e: Exception) { + client.resultAsEmail(email) + return } + // + // ... process directly ... + } } // diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/ProfileService.kt b/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/ProfileService.kt index e55a64ef..230326f6 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/ProfileService.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/ProfileService.kt @@ -12,62 +12,59 @@ import kotlin.time.Duration.Companion.seconds @VirtualObject class ProfileService { - companion object { - // - private val USER = StateKey.of("user", KtSerdes.json()) - // - } + companion object { + // + private val USER = StateKey.of("user", KtSerdes.json()) + // + } - // - @Handler - suspend fun userEvent(ctx: ObjectContext, name: String) { - // - val profile = UserProfile(ctx.key(), name) - // - ctx.set(USER, profile) - // + // + @Handler + suspend fun userEvent(ctx: ObjectContext, name: String) { + // + val profile = UserProfile(ctx.key(), name) + // + ctx.set(USER, profile) + // - // - ProfileServiceClient - .fromContext(ctx, ctx.key()) - .send(1.seconds) - .emit() - // - } + // + ProfileServiceClient.fromContext(ctx, ctx.key()).send(1.seconds).emit() + // + } - // - @Handler - suspend fun featureEvent(ctx: ObjectContext, email: String) { - // - // - val user = ctx.get(USER) ?: throw TerminalException("No user found") - // - user.email = email + // + @Handler + suspend fun featureEvent(ctx: ObjectContext, email: String) { + // + // + val user = ctx.get(USER) ?: throw TerminalException("No user found") + // + user.email = email - // - ctx.set(USER, user) - // - } + // + ctx.set(USER, user) + // + } - // - @Handler - suspend fun emit(ctx: ObjectContext) { - // - // - val user = ctx.get(USER) ?: throw TerminalException("No user found") - // + // + @Handler + suspend fun emit(ctx: ObjectContext) { + // + // + val user = ctx.get(USER) ?: throw TerminalException("No user found") + // - send(ctx.key(), user) + send(ctx.key(), user) - // - ctx.clearAll() - // - } + // + ctx.clearAll() + // + } } // class UserProfile(val id: String, val name: String) { - var email: String? = null + var email: String? = null } -fun send(key: String, user: UserProfile) {} \ No newline at end of file +fun send(key: String, user: UserProfile) {} diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/UserUpdatesService.kt b/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/UserUpdatesService.kt index f4911c71..75dfa9fa 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/UserUpdatesService.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/eventprocessing/UserUpdatesService.kt @@ -2,7 +2,6 @@ package usecases.eventprocessing import dev.restate.sdk.annotation.Handler import dev.restate.sdk.annotation.VirtualObject -import dev.restate.sdk.kotlin.KtSerdes import dev.restate.sdk.kotlin.ObjectContext import dev.restate.sdk.kotlin.runBlock import kotlin.time.Duration.Companion.milliseconds @@ -10,49 +9,45 @@ import kotlin.time.Duration.Companion.milliseconds // @VirtualObject class UserUpdatesService { - // - @Handler - suspend fun updateUserEvent(ctx: ObjectContext, event: UserUpdate) { - // - // - var userId = ctx.runBlock { updateUserProfile(event.profile) } - - // - - // - while (userId == "NOT_READY") { - // - ctx.sleep(5000.milliseconds) - // - // - userId = ctx.runBlock { updateUserProfile(event.profile) } - // - } - - val finalUserId = userId - // - val roleId = ctx.runBlock { - setUserPermissions(finalUserId, event.permissions) - } - ctx.runBlock { - provisionResources(finalUserId, roleId, event.resources) - } - // + // + @Handler + suspend fun updateUserEvent(ctx: ObjectContext, event: UserUpdate) { + // + // + var userId = ctx.runBlock { updateUserProfile(event.profile) } + + // + + // + while (userId == "NOT_READY") { + // + ctx.sleep(5000.milliseconds) + // + // + userId = ctx.runBlock { updateUserProfile(event.profile) } + // } -// + + val finalUserId = userId + // + val roleId = ctx.runBlock { setUserPermissions(finalUserId, event.permissions) } + ctx.runBlock { provisionResources(finalUserId, roleId, event.resources) } + // + } + // } // class UserUpdate(var profile: String, var permissions: String, var resources: String) fun updateUserProfile(profile: String): String { - return if (Math.random() < 0.8) "NOT_READY" else "$profile-id" + return if (Math.random() < 0.8) "NOT_READY" else "$profile-id" } fun setUserPermissions(userId: String?, permissions: String): String { - return permissions + return permissions } fun provisionResources(userId: String?, role: String?, resources: String?): String { - return "" + return "" } diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/microservices/Idempotency.kt b/code_snippets/kotlin/src/main/kotlin/usecases/microservices/Idempotency.kt index afc4149b..709e2425 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/microservices/Idempotency.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/microservices/Idempotency.kt @@ -4,23 +4,22 @@ import dev.restate.sdk.client.CallRequestOptions import dev.restate.sdk.client.Client class Config { - companion object { - var RESTATE_URL = "http://localhost:8080" - } + companion object { + const val RESTATE_URL = "http://localhost:8080" + } } class Idempotency { - // - val rs = Client.connect(Config.RESTATE_URL) + // + val rs = Client.connect(Config.RESTATE_URL) - suspend fun reserveProduct(productId: String, reservationId: String) { - // - ProductServiceClient.fromClient(rs, productId) - .send() - .reserve(CallRequestOptions.DEFAULT.withIdempotency(reservationId)) - // - } - // - -} \ No newline at end of file + suspend fun reserveProduct(productId: String, reservationId: String) { + // + ProductServiceClient.fromClient(rs, productId) + .send() + .reserve(CallRequestOptions.DEFAULT.withIdempotency(reservationId)) + // + } + // +} diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/microservices/ProductService.kt b/code_snippets/kotlin/src/main/kotlin/usecases/microservices/ProductService.kt index 8b8db4f2..7a834556 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/microservices/ProductService.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/microservices/ProductService.kt @@ -1,3 +1,5 @@ +@file:Suppress("ktlint:standard:filename") + package usecases.microservices import dev.restate.sdk.annotation.Handler @@ -5,10 +7,10 @@ import dev.restate.sdk.annotation.VirtualObject import dev.restate.sdk.kotlin.ObjectContext @VirtualObject -class ProductService { +public class ProductService { - @Handler - suspend fun reserve(ctx: ObjectContext): Boolean { - return true; - } -} \ No newline at end of file + @Handler + suspend fun reserve(ctx: ObjectContext): Boolean { + return true + } +} diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/microservices/RoleUpdateService.kt b/code_snippets/kotlin/src/main/kotlin/usecases/microservices/RoleUpdateService.kt index 2451618f..3caff888 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/microservices/RoleUpdateService.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/microservices/RoleUpdateService.kt @@ -11,60 +11,60 @@ import kotlinx.serialization.Serializable // @Service class RoleUpdateService { - // + // -// -// - @Handler - suspend fun applyRoleUpdate(ctx: Context, update: UpdateRequest) { + // + // + @Handler + suspend fun applyRoleUpdate(ctx: Context, update: UpdateRequest) { // // // - val previousRole = ctx.runBlock { getCurrentRole(update.userId) } - ctx.runBlock { tryApplyUserRole(update.userId, update.role) } + val previousRole = ctx.runBlock { getCurrentRole(update.userId) } + ctx.runBlock { tryApplyUserRole(update.userId, update.role) } // - val previousPermissions = mutableListOf() - for (permission in update.permissions) { - // - try { - // - val previous: Permission = ctx.runBlock { - tryApplyPermission(update.userId, permission) - } - // - previousPermissions.add(previous) // remember the previous setting - } catch (err: TerminalException) { - rollback(ctx, update.userId, previousRole, previousPermissions) - throw err - } - // - } + val previousPermissions = mutableListOf() + for (permission in update.permissions) { + // + try { + // + val previous: Permission = ctx.runBlock { tryApplyPermission(update.userId, permission) } + // + previousPermissions.add(previous) // remember the previous setting + } catch (err: TerminalException) { + rollback(ctx, update.userId, previousRole, previousPermissions) + throw err + } + // } + } } // fun tryApplyPermission(id: String?, permission: Permission): Permission { - return Permission("", "") + return Permission("", "") } fun getCurrentRole(name: String?): UserRole { - return UserRole("", "") + return UserRole("", "") } fun tryApplyUserRole(name: String?, role: String?): UserRole { - return UserRole("", "") + return UserRole("", "") } -fun rollback(ctx: Context, user: String, role: UserRole, previousPermissions: MutableList) { -} +fun rollback( + ctx: Context, + user: String, + role: UserRole, + previousPermissions: MutableList, +) {} @Serializable data class UpdateRequest(val userId: String, val role: String, val permissions: Array) -@Serializable -data class UserRole(val roleKey: String, val roleDescription: String) +@Serializable data class UserRole(val roleKey: String, val roleDescription: String) -@Serializable -data class Permission(val permissionKey: String, val setting: String) \ No newline at end of file +@Serializable data class Permission(val permissionKey: String, val setting: String) diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/workflows/SignupWorkflow.kt b/code_snippets/kotlin/src/main/kotlin/usecases/workflows/SignupWorkflow.kt index 01b9c3a1..b6b87897 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/workflows/SignupWorkflow.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/workflows/SignupWorkflow.kt @@ -4,84 +4,84 @@ import dev.restate.sdk.annotation.Handler import dev.restate.sdk.annotation.Workflow import dev.restate.sdk.common.TerminalException import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder -import dev.restate.sdk.kotlin.* +import dev.restate.sdk.kotlin.KtDurablePromiseKey +import dev.restate.sdk.kotlin.KtStateKey +import dev.restate.sdk.kotlin.SharedWorkflowContext +import dev.restate.sdk.kotlin.WorkflowContext +import dev.restate.sdk.kotlin.runBlock import kotlinx.serialization.Serializable // @Workflow class SignupWorkflow { - companion object { - private val STAGE = KtStateKey.json("stage") - private val EMAIL_LINK = KtDurablePromiseKey.json("email-link") - } + companion object { + private val STAGE = KtStateKey.json("stage") + private val EMAIL_LINK = KtDurablePromiseKey.json("email-link") + } - // - @Workflow - suspend fun run(ctx: WorkflowContext, user: User): Boolean { - // - ctx.set(STAGE, "Creating user") - // - // - ctx.runBlock { createUserEntry(ctx.key(), user.name) } - // + // + @Workflow + suspend fun run(ctx: WorkflowContext, user: User): Boolean { + // + ctx.set(STAGE, "Creating user") + // + // + ctx.runBlock { createUserEntry(ctx.key(), user.name) } + // - // - ctx.set(STAGE, "Email verification") - // - // - val secret = ctx.random().nextUUID().toString() - ctx.runBlock { sendEmailWithLink(user.email, secret) } - // + // + ctx.set(STAGE, "Email verification") + // + // + val secret = ctx.random().nextUUID().toString() + ctx.runBlock { sendEmailWithLink(user.email, secret) } + // - // - val clickSecret = ctx.promise(EMAIL_LINK).awaitable().await() - // - // - if (clickSecret != secret) { - // - ctx.set(STAGE, "Verification failed") - // - throw TerminalException("Wrong secret from email link") - } - // - // - ctx.set(STAGE, "User verified") - // - return true + // + val clickSecret = ctx.promise(EMAIL_LINK).awaitable().await() + // + // + if (clickSecret != secret) { + // + ctx.set(STAGE, "Verification failed") + // + throw TerminalException("Wrong secret from email link") } - // + // + // + ctx.set(STAGE, "User verified") + // + return true + } + // - // - @Handler - suspend fun getStage(ctx: SharedWorkflowContext): String? { - return ctx.get(STAGE) - } - // + // + @Handler + suspend fun getStage(ctx: SharedWorkflowContext): String? { + return ctx.get(STAGE) + } + // - // - @Handler - suspend fun approveEmail(ctx: SharedWorkflowContext, secret: String) { - ctx.promiseHandle(EMAIL_LINK).resolve(secret) - } + // + @Handler + suspend fun approveEmail(ctx: SharedWorkflowContext, secret: String) { + ctx.promiseHandle(EMAIL_LINK).resolve(secret) + } - @Handler - suspend fun rejectEmail(ctx: SharedWorkflowContext) { - ctx.promiseHandle(EMAIL_LINK).reject("Abort verification") - } - // + @Handler + suspend fun rejectEmail(ctx: SharedWorkflowContext) { + ctx.promiseHandle(EMAIL_LINK).reject("Abort verification") + } + // } // fun main(args: Array) { - RestateHttpEndpointBuilder - .builder() - .bind(SignupWorkflow()) - .buildAndListen() + RestateHttpEndpointBuilder.builder().bind(SignupWorkflow()).buildAndListen() } fun createUserEntry(id: String?, name: String?) {} fun sendEmailWithLink(email: String?, secret: String?) {} -@Serializable -data class User(val id: String, val email: String, val name: String) \ No newline at end of file +@Serializable data class User(val id: String, val email: String, val name: String) diff --git a/code_snippets/kotlin/src/main/kotlin/usecases/workflows/WorkflowSubmitter.kt b/code_snippets/kotlin/src/main/kotlin/usecases/workflows/WorkflowSubmitter.kt index d94e0068..537c38fa 100644 --- a/code_snippets/kotlin/src/main/kotlin/usecases/workflows/WorkflowSubmitter.kt +++ b/code_snippets/kotlin/src/main/kotlin/usecases/workflows/WorkflowSubmitter.kt @@ -3,24 +3,25 @@ package usecases.workflows import dev.restate.sdk.client.Client class WorkflowSubmitter { - suspend fun submit(user: User) { - // - // import dev.restate.sdk.client.Client; - val rs = Client.connect("http://localhost:8080") + suspend fun submit(user: User) { + // + // import dev.restate.sdk.client.Client; + val rs = Client.connect("http://localhost:8080") + // mark + SignupWorkflowClient.fromClient(rs, user.id) // mark - SignupWorkflowClient.fromClient(rs, user.id) - // mark - .submit(user) + .submit(user) - // do something else, with workflow running in the background + // do something else, with workflow running in the background - // attach back to the workflow - // mark - val result = SignupWorkflowClient.fromClient(rs, user.id) + // attach back to the workflow + // mark + val result = + SignupWorkflowClient.fromClient(rs, user.id) // mark .workflowHandle() // mark .attach() - // - } -} \ No newline at end of file + // + } +}