Skip to content

Commit 7cc0164

Browse files
Fix for kotlin await
1 parent e6a8c5c commit 7cc0164

3 files changed

Lines changed: 24 additions & 2 deletions

File tree

sdk-api-kotlin/src/main/kotlin/dev/restate/sdk/kotlin/ContextImpl.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import kotlin.jvm.optionals.getOrNull
2727
import kotlin.time.Duration
2828
import kotlin.time.toJavaDuration
2929
import kotlinx.coroutines.*
30-
import kotlinx.coroutines.future.await
3130

3231
internal class ContextImpl
3332
internal constructor(

sdk-api-kotlin/src/main/kotlin/dev/restate/sdk/kotlin/Util.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,33 @@
99
package dev.restate.sdk.kotlin
1010

1111
import dev.restate.common.Slice
12+
import dev.restate.sdk.common.AbortedExecutionException
1213
import dev.restate.sdk.endpoint.definition.HandlerContext
1314
import dev.restate.serde.Serde
15+
import java.util.concurrent.CompletionStage
1416
import kotlinx.coroutines.CancellationException
17+
import kotlinx.coroutines.future.await as kotlinxAwait
18+
19+
/**
20+
* Awaits [this], translating the SDK-internal [AbortedExecutionException] control-flow signal into
21+
* a coroutine [CancellationException].
22+
*
23+
* The state machine unwinds a suspended or closed invocation by completing the awaited future
24+
* exceptionally with [AbortedExecutionException] — a bare [Throwable] the Java SDK sneaky-throws.
25+
* Letting that raw throwable surface into coroutine code is not idiomatic: it is not a
26+
* [CancellationException], so structured concurrency treats it as a genuine failure and a user
27+
* `catch (e: Throwable)` would silently swallow the suspension instead of propagating it. Wrapping
28+
* it as [CancellationException] keeps invocation suspension behaving like ordinary coroutine
29+
* cancellation, as it did before the shared-core state machine contract.
30+
*
31+
* All SDK await sites go through this wrapper (instead of `kotlinx.coroutines.future.await`).
32+
*/
33+
internal suspend fun <T> CompletionStage<T>.await(): T =
34+
try {
35+
this.kotlinxAwait()
36+
} catch (e: AbortedExecutionException) {
37+
throw CancellationException("Restate invocation suspended or closed").apply { initCause(e) }
38+
}
1539

1640
internal fun <T : Any?> Serde<T>.serializeWrappingException(
1741
handlerContext: HandlerContext,

sdk-api-kotlin/src/main/kotlin/dev/restate/sdk/kotlin/futures.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import kotlin.time.Duration
2323
import kotlin.time.toJavaDuration
2424
import kotlinx.coroutines.CoroutineScope
2525
import kotlinx.coroutines.currentCoroutineContext
26-
import kotlinx.coroutines.future.await
2726
import kotlinx.coroutines.launch
2827

2928
internal abstract class BaseDurableFutureImpl<T : Any?> : DurableFuture<T> {

0 commit comments

Comments
 (0)