kotlinkotlin-coroutinescoroutine

Why is exception handled by the handler of a child coroutine not parent?


I',m trying to test coroutineExceptionHandler.

Here is my code.

fun main(): Unit = runBlocking {
    code1_9()
}

fun createExceptionHandler(name: String) = CoroutineExceptionHandler { context, throwable ->
    println("[${Thread.currentThread().name} - $name] Caught $throwable")
}

suspend fun code1_9() = coroutineScope {
    val supervisorScope = CoroutineScope(SupervisorJob() + createExceptionHandler("supervisor"))
    supervisorScope.apply {
        launch(CoroutineName("launch1") + createExceptionHandler("launch1")) {
            throw Exception("[${Thread.currentThread().name}] Error !")
        }
        launch(CoroutineName("launch2")) {
            println("[${Thread.currentThread().name}] launch2")
        }
    }
    delay(1000L)
}

Result:

[DefaultDispatcher-worker-2 @launch2#3] launch2
[DefaultDispatcher-worker-1 @launch1#2 - launch1] Caught java.lang.Exception: [DefaultDispatcher-worker-1 @launch1#2] Error !

I expect supervisorScope's handler will be chosen, but launch handler caught the exception.

Why the exception caught in child coroutine? Isn't the supervisorScope root coroutine?


Solution

  • What you are doing is similar to:

    supervisorScope.launch(CoroutineName("launch1") + createExceptionHandler("launch1")) {
        throw Exception("[${Thread.currentThread().name}] Error !")
    }
    
    supervisorScope.launch(CoroutineName("launch2")) {
        println("[${Thread.currentThread().name}] launch2")
    }
    

    To make the parent handle the exception change apply to launch

    supervisorScope.launch {
        launch(CoroutineName("launch1") + createExceptionHandler("launch1")) {
            throw Exception("[${Thread.currentThread().name}] Error !")
        }
        launch(CoroutineName("launch2")) {
            println("[${Thread.currentThread().name}] launch2")
        }
    }