nacyolsa
12/14/2022, 9:52 AMShiftCancellationException(Shifted Continuation)
is it some known issue?simon.vergauwen
12/14/2022, 10:02 AMsimon.vergauwen
12/14/2022, 10:03 AMbind
or shift
somewhere into an outer scope, or you're capturing and logging CancellationException
which is not allowed in Kotlin.
CancellationException
is a special case exception in Kotlin Coroutines.nacyolsa
12/14/2022, 10:29 AMCan you share any related code?At this moment I can't. I will try to prepare steps to reproduce later.
shift
I use only in a few places. I checked if any bind
is missing by using a new plugin and looks like everything is fine.simon.vergauwen
12/14/2022, 10:44 AMbind
, it comes from using it in places where you leak it outside of it's scope. This is a known issue with DSLs like the once we have in Kotlin, where you leak functionality outside of their DSL scopes.
For example:
val res = either<String, () -> Int> {
{ "fail".left().bind() }
} // Either.Right(Function1)
res.orNull()?.invoke() // throws ShiftCancellationException
This happens because bind
is leaked outside of the either { }
scope. I see it's this part is cut-off by Dokka on the website 😞 Here is a link to the docs in KDoc with some more details, https://github.com/arrow-kt/arrow/blob/99e50bd2b5dfcc452d401fc8acfdffd7172d685a/ar[…]w-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt
Another problematic usage, but this is also not specific to Arrow but to the Kotlin Coroutine system is that you cannot capture CancellationException
. I.e.
either<String, Unit> {
try {
shift("fail")
} catch(e: Throwable) {
println(e)
}
}
Here CancellationException
is swallowed which violates Kotlin Coroutines. This would print ShiftCancellationException
, and would result in Either.Right(Unit)
.simon.vergauwen
12/14/2022, 10:46 AMRuntimeException
instead of CancellationException
with a better descriptive message. Which is what I am investigating now.
The second case would be considered a bug in Kotlin, and there is not much we can do about it. Perhaps improve the message
of the CancellationException
? 🤔Stylianos Gakis
12/14/2022, 10:50 AMrunCatching
also catches Throwable and therefore CancellationException and people assume that this is okay to do.
It’s really nice that Either.catch
doesn’t do that and properly handles this case, but obviously most people aren’t gonna use that by default.simon.vergauwen
12/14/2022, 10:52 AMrunCatching
makes sense... Result
& co was made for the internal machinery of Continuation
and was never meant for public use.
Since it's now in everyones binary, they cannot simply change its behavior without breaking code. Changing the usages might break the binaries in some cases.
It should've never become public. (Change my mind) 😄simon.vergauwen
12/14/2022, 10:52 AMStylianos Gakis
12/14/2022, 10:53 AMsimon.vergauwen
12/14/2022, 10:55 AMsimon.vergauwen
12/14/2022, 10:57 AMsuspend
, but it also applies to all inline fun
because suspend
can pass through inline fun
.Stylianos Gakis
12/14/2022, 11:01 AMsimon.vergauwen
12/14/2022, 11:03 AMsimon.vergauwen
12/14/2022, 12:47 PMCLOVIS
12/14/2022, 1:07 PMrunCatching
is incompatible with structured concurrency.nacyolsa
12/14/2022, 1:09 PMinternal suspend fun <RESPONSE : Any> invoke(request: DaprRequest, type: KClass<RESPONSE>): Either<MessagingError, RESPONSE?> =
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
Either.catch {
daprClient.invokeMethod(request.toInvokeMethodRequest(appId), TypeRef.get(type.javaObjectType))
.awaitSingleOrNull()
}.mapLeft {
logger.error(it) { it.message }
MessagingError(message = "Failed to call Dapr $appId request: $request", cause = it, isRecoverable = false)
}
}
It helped me to localize that withContext(<http://Dispatchers.IO|Dispatchers.IO>)
is not needed here at all. After removing withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
issue doesn't occur. It also doesn't occur when I change IO
dispatcher to Dispatchers.Unconfined
.simon.vergauwen
12/14/2022, 1:11 PMShiftCancellationException
. There is no shift
, bind
or either { }
within this code 😕Wesley Hartford
12/14/2022, 4:46 PMShiftCancellationException
when building a Flow
inside an either {}
and one of the steps in my Flow
calls shift
or bind
. I understand the problem and generally know how to fix it, but I still write it frequently.