coroutineScope: cancellation-exception-only-stops-the-throwing-child
CancellationException only stops the child co-routine that threw it allowing others to finish.
GT-Sandbox-Snapshot
Code
package com.glassthought.sandbox
import com.glassthought.sandbox.util.out.impl.out
import gt.sandbox.util.output.Out
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.system.exitProcess
import kotlin.time.Duration.Companion.seconds
private suspend fun mainImpl(out: Out) {
coroutineScope {
foo()
}
}
private suspend fun foo() {
val result = out.actionWithMsg("functionThatStartsCoRoutineScope()", { functionThatStartsCoRoutineScope() })
out.info("Result from functionThatStartsCoRoutineScope() is: $result")
}
private suspend fun functionThatStartsCoRoutineScope(): String {
return coroutineScope {
out.info("This coroutineScope suspends the calling function.")
val resultDeferred = async(CoroutineName("async-wait-3s")) {
out.delayNamed(3.seconds)
"result-from-async-wait-3s"
}
async(CoroutineName("async-throws-cancellation-after-2s")) {
out.delayNamed(2.seconds, "delay before throwing CancellationException")
out.info("OK I am throwing CancellationException now!")
throw CancellationException("I am throwing cancellation")
}
launch(CoroutineName("launch-waits-1s")) {
out.delayNamed(1.seconds)
}
out.info("Just launched co-routines")
resultDeferred.await()
}
}
fun main(): Unit = runBlocking {
out.info("START - ON MAIN")
try {
mainImpl(out)
} catch (e: Exception) {
out.error("back at MAIN got an exception! of type=[${e::class.simpleName}] with msg=[${e.message}] cause=[${e.cause}]. Exiting with error code 1")
exitProcess(1)
}
out.info("DONE - WITHOUT errors on MAIN")
}
Command to reproduce:
gt.sandbox.checkout.commit aa4b136e407661c441cc \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"
Recorded output of command:
Picked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debug
Picked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debug
[INFO][elapsed: 14ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] START - ON MAIN
[INFO][elapsed: 30ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] [>] Starting action=[functionThatStartsCoRoutineScope()]
[INFO][elapsed: 30ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] This coroutineScope suspends the calling function.
[INFO][elapsed: 32ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Just launched co-routines
[INFO][elapsed: 36ms][🥇][⓶][coroutname:@async-wait-3s#2][tname:main/tid:1] Delaying for 3s what_for=[]
[INFO][elapsed: 37ms][🥇][⓷][coroutname:@async-throws-cancellation-after-2s#3][tname:main/tid:1] Delaying for 2s what_for=[delay before throwing CancellationException]
[INFO][elapsed: 37ms][🥇][⓸][coroutname:@launch-waits-1s#4][tname:main/tid:1] Delaying for 1s what_for=[]
[INFO][elapsed: 1038ms][🥇][⓸][coroutname:@launch-waits-1s#4][tname:main/tid:1] Done delaying for 1s what_for=[]
[INFO][elapsed: 2037ms][🥇][⓷][coroutname:@async-throws-cancellation-after-2s#3][tname:main/tid:1] Done delaying for 2s what_for=[delay before throwing CancellationException]
[INFO][elapsed: 2038ms][🥇][⓷][coroutname:@async-throws-cancellation-after-2s#3][tname:main/tid:1] OK I am throwing CancellationException now!
[INFO][elapsed: 3036ms][🥇][⓶][coroutname:@async-wait-3s#2][tname:main/tid:1] Done delaying for 3s what_for=[]
[INFO][elapsed: 3038ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] [<] Finished action=[functionThatStartsCoRoutineScope()].
[INFO][elapsed: 3038ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Result from functionThatStartsCoRoutineScope() is: result-from-async-wait-3s
[INFO][elapsed: 3038ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] DONE - WITHOUT errors on MAIN
Backlinks