Vsevolod Ganin
12/05/2019, 11:06 AMCoroutineExceptionHandler installed in top-most runBlocking is not being called? I read all docs but can’t quite grasp the sense of it. Example:
fun main(): Unit = runBlocking(CoroutineExceptionHandler { _, e ->
println("Boom: $e")
}) {
(0..10).map {
launch {
println("Throw in attempt #$it")
throw RuntimeException("Attempt #$it")
}
}
Unit
}streetsofboston
12/05/2019, 12:49 PMlaunc(ceh) {...} instead?Vsevolod Ganin
12/05/2019, 12:57 PMVsevolod Ganin
12/05/2019, 1:00 PMlaunch with supervisorScope helps thoughstreetsofboston
12/05/2019, 1:04 PMVsevolod Ganin
12/05/2019, 1:20 PMstreetsofboston
12/05/2019, 2:38 PMsuspend functions and such:
https://medium.com/the-kotlin-chronicle/coroutine-exceptions-3378f51a7d33Vsevolod Ganin
12/05/2019, 2:46 PMstreetsofboston
12/05/2019, 2:47 PMVsevolod Ganin
12/05/2019, 3:28 PMfun main(): Unit = runBlocking {
val errorHandler = CoroutineExceptionHandler { _, e ->
println("Boom: $e")
}
val scope = CoroutineScope(errorHandler)
scope.launch {
throw RuntimeException()
}
Unit
}
It does not crash and it does not print anything at all. The code is similar to one you have in the blogspotstreetsofboston
12/05/2019, 3:31 PMfun main() {
val ceh = CoroutineExceptionHandler { _, e ->
println("CEH Handled Crash [$e]")
}
CoroutineScope(context + ceh).launch {
oops()
}
Thread.sleep(1000)
}
context is just a dispatcher…streetsofboston
12/05/2019, 3:32 PMrunBlocking provides the top-most scope and it handles the exception. I think it just throws it to the caller of `runBlocking`…., even though you create a brand new top-scope right in your sample…. needs more investigation 🙂Vsevolod Ganin
12/05/2019, 3:35 PMrunBlocking catches the exceptionstreetsofboston
12/05/2019, 3:37 PMval scope = CoroutineScope(errorHandler) into val scope = CoroutineScope(otherDispatcher + errorHandler) where otherDispatcher is a different dispatcher than the one the runBlocking is using…. It shouldn’t matter, but i’m curious….Vsevolod Ganin
12/05/2019, 3:37 PMstreetsofboston
12/05/2019, 3:38 PMVsevolod Ganin
12/05/2019, 3:38 PMthrow it disconnects 😞streetsofboston
12/05/2019, 3:43 PMVsevolod Ganin
12/05/2019, 3:49 PMfun main(): Unit = runBlocking {
val errorHandler = CoroutineExceptionHandler { _, e ->
println("Boom: $e")
}
val scope = CoroutineScope(errorHandler)
scope.launch {
throw RuntimeException()
}.join()
Unit
}Vsevolod Ganin
12/05/2019, 3:50 PMjoinVsevolod Ganin
12/05/2019, 3:53 PMjoin I’m able to go further nowalllex
12/05/2019, 4:19 PMlaunch running under a SupervisorJob. If you call async under supervisor, the exections are caught be the Deferred job, and will be rethrown when await is invoked. Therefore they are not “uncaught”. Calling both launch or async under a regular Job results in rethrown/propagated exceptions as well. Therefore they are not “uncaught” either.
So, in your original example you either need to launch under a supervisorScope , or you need to wrap your runBlocking in try-catch.
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/Vsevolod Ganin
12/05/2019, 4:47 PMawaitstreetsofboston
12/05/2019, 4:57 PMawait() allows you to try-catch an exception. Still, if the top-most scope called launch , its CEH will still be handling that exception. From my blog-post:
> We need to be aware that even if we handle the exception by calling await(), it will still go up the child-parent Coroutine chain.Vsevolod Ganin
12/05/2019, 5:08 PMasync ? If we don’t call await the CEH on top will not get the exception. This is consistent with explanation above: the async handles the exception so it is not given to CEH. But if a user ceases to call await (let’s imagine he forgets) then the exception is lost. Example:
fun main() = runBlocking {
val scope = CoroutineScope(CoroutineExceptionHandler { _, e ->
println("Boom: $e")
})
scope.async {
throw RuntimeException()
}.join()
}alllex
12/05/2019, 7:05 PM