Skip to content

CoroutineExceptionHandler installed in top(-most) scope not always used. #1157

Open
@streetsofboston

Description

@streetsofboston

I have this example code-snippet:

val xHandlerParent = CoroutineExceptionHandler { c, e ->
    println("Parent Handled Crash")
}

val xHandlerLeaf = CoroutineExceptionHandler { c, e ->
    println("Leaf Handled Crash")
}

fun test1() {
    // Exception throw up the call-stack. Expected
    CoroutineScope(Job()).launch {
        delay(1000)
        throw Exception("Some Exception 1")
    }

    Thread.sleep(2000)
}

fun test2() {
    // Exception handled by xHandlerParent: Expected
    CoroutineScope(xHandlerParent).launch {
        delay(1000)
        throw Exception("Some Exception 1")
    }

    Thread.sleep(2000)
}

fun test3() {
    // Exception handled by xHandlerLeaf: Expected?
    // Yes, since there is a top scope with a CoroutineExceptionHandler.
    // No,  since the top-most scope does not have CoroutineExceptionHandler.
    CoroutineScope(Job()).launch(xHandlerLeaf) {
        delay(1000)
        throw Exception("Some Exception 1")
    }

    Thread.sleep(2000)
}

fun test4() {
    // Exception handled by xHandlerLeaf. Unexpected.
    // Shouldn't it be handled by xHandlerParent instead?
    CoroutineScope(xHandlerParent).launch(xHandlerLeaf) {
        delay(1000)
        throw Exception("Some Exception 1")
    }

    Thread.sleep(2000)
}

fun test5() {
    // Exception handled by xHandlerParent: Expected
    CoroutineScope(xHandlerParent).launch {
        withContext(xHandlerLeaf) {
            delay(1000)
            throw Exception("Some Exception 1")
        }
    }

    Thread.sleep(2000)
}

fun test6() {
    // Exception handled by xHandlerParent: Expected?
    // Yes, since there is a top scope with a CoroutineExceptionHandler.
    // No,  since the top-most scope does not have CoroutineExceptionHandler.
    CoroutineScope(Job()).launch(xHandlerParent) {
        launch(xHandlerLeaf) {
            delay(1000)
            throw Exception("Some Exception 1")
        }
    }

    Thread.sleep(2000)
}

fun test7() {
    // Exception thrown up the call-stack. Expected?
    // Yes, since the top-most scope does not have CoroutineExceptionHandler.
    // No, since there is a top scope with a CoroutineExceptionHandler.
    CoroutineScope(Job()).launch {
        withContext(xHandlerLeaf) {
            delay(1000)
            throw Exception("Some Exception 1")
        }
    }

    Thread.sleep(2000)
}

My questions are:

  • Is the top-most scope always used and if it has CoroutineExceptionHandler, it will be used, otherwise, the exception is thrown up the call-stack?
  • Or is the top scope that has a CoroutineExceptionHandler used instead? Only if no such top scope can be found, the exception is thrown up the call-stack.
  • Regardless of the answer to the previous question, why does the example of test4() not use the xHandlerParent, since that is the CoroutineExceptionHandler of the top and top-most scope?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions