⚠️ join() does NOT rethrow ⚠️
Unlike await()
which does rethrow, join() just waits for co-routine to complete, without care of whether completion was successful or failure.
⚠️ join() does NOT rethrow code example ⚠️
Code
package com.glassthought.sandbox
import gt.sandbox.util.output.Emojis
import gt.sandbox.util.output.Out
import kotlinx.coroutines.*
import kotlin.system.exitProcess
import kotlin.time.Duration.Companion.milliseconds
fun main(): Unit = runBlocking {
val out = Out.standard()
out.info("START")
try {
mainImpl(out)
} catch (e: Exception) {
out.error("in 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")
}
private suspend fun mainImpl(out: Out) {
val parentJob = Job()
val scope = CoroutineScope(parentJob)
out.info("Launching coroutine that will throw exception...")
val job = scope.launch {
out.info("Launch coroutine started")
out.delayLogsCancellation(500.milliseconds)
throw MyExceptionWillThrowFromCoroutine.create("Exception from launch", out)
}
out.actionWithMsg("job.join()", { job.join() })
out.infoPrintState(job, "launchJob")
out.infoPrintState(scope, "scope-where-we-launched")
}
class MyExceptionWillThrowFromCoroutine private constructor(msg: String) : RuntimeException(msg) {
companion object {
suspend fun create(msg: String, out: Out): MyExceptionWillThrowFromCoroutine {
val exc = MyExceptionWillThrowFromCoroutine(msg)
out.warn("${Emojis.EXCEPTOIN} throwing exception=[${exc::class.simpleName}] with msg=[${msg}]")
return exc
}
}
}
Command to reproduce:
gt.sandbox.checkout.commit 73693c5d8d2ddb27f9a7 \
&& 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
[INFO][elapsed: 29ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Launching coroutine that will throw exception...
[INFO][elapsed: 34ms][2️⃣][⓶][coroutname:@coroutine#2][tname:DefaultDispatcher-worker-1/tid:31] Launch coroutine started
[INFO][elapsed: 34ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Performing action=[job.join()]
[WARN][elapsed: 569ms][2️⃣][⓶][coroutname:@coroutine#2][tname:DefaultDispatcher-worker-1/tid:31] 💥 throwing exception=[MyExceptionWillThrowFromCoroutine] with msg=[Exception from launch]
Exception in thread "DefaultDispatcher-worker-1 @coroutine#2" com.glassthought.sandbox.MyExceptionWillThrowFromCoroutine: Exception from launch
at com.glassthought.sandbox.MyExceptionWillThrowFromCoroutine$Companion.create(Main.kt:46)
at com.glassthought.sandbox.MainKt$mainImpl$job$1.invokeSuspend(Main.kt:34)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineId(2), "coroutine#2":StandaloneCoroutine{Cancelling}@e541635, Dispatchers.Default]
[INFO][elapsed: 576ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Performed action=[job.join()]
[INFO][elapsed: 579ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] State of [launchJob]:
launchJob.isActive | false
launchJob.isCancelled | true
launchJob.isCompleted | true
[INFO][elapsed: 579ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] State of [scope-where-we-launched]: isActive=false
[INFO][elapsed: 580ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] DONE - WITHOUT errors on main
Backlinks