CoroutineExceptionHandler only works with launch
CoroutineExceptionHandler processes uncaught exception from launch
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 coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
runBlocking {
out.info("${Emojis.CHECK_MARK} CoroutineExceptionHandler CALLED!")
out.info("CoroutineExceptionHandler is called with throwable: ${throwable::class.simpleName} - ${throwable.message}")
}
}
val parentJob = Job()
val scope = CoroutineScope(parentJob + coroutineExceptionHandler)
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")
scope.cancel()
}
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 a7bc470832057f8c7ff6 \
&& 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: 20ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] START
[INFO][elapsed: 40ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Launching coroutine that will throw exception...
[INFO][elapsed: 46ms][2️⃣][⓶][coroutname:@coroutine#2][tname:DefaultDispatcher-worker-1/tid:31] Launch coroutine started
[INFO][elapsed: 46ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Performing action=[job.join()]
[WARN][elapsed: 582ms][2️⃣][⓶][coroutname:@coroutine#2][tname:DefaultDispatcher-worker-1/tid:31] 💥 throwing exception=[MyExceptionWillThrowFromCoroutine] with msg=[Exception from launch]
[INFO][elapsed: 584ms][2️⃣][⓷][coroutname:@coroutine#3][tname:DefaultDispatcher-worker-1/tid:31] ✅ CoroutineExceptionHandler CALLED!
[INFO][elapsed: 585ms][2️⃣][⓷][coroutname:@coroutine#3][tname:DefaultDispatcher-worker-1/tid:31] CoroutineExceptionHandler is called with throwable: MyExceptionWillThrowFromCoroutine - Exception from launch
[INFO][elapsed: 586ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] Performed action=[job.join()]
[INFO][elapsed: 589ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] State of [launchJob]:
launchJob.isActive | false
launchJob.isCancelled | true
launchJob.isCompleted | true
[INFO][elapsed: 589ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] State of [scope-where-we-launched]: isActive=false
[INFO][elapsed: 589ms][🥇][①][coroutname:@coroutine#1][tname:main/tid:1] DONE - WITHOUT errors on main
Backlinks