Elye
Elye

Reputation: 60081

Why can't runBlocking take in CoroutineExceptionHandler?

When I have

    @Test
    fun test() {
        val handler = CoroutineExceptionHandler { _, exception ->
            println("CoroutineExceptionHandler got $exception")
        }

        GlobalScope.launch(handler) {
            throw IllegalAccessException("Just testing")
        }

        Thread.sleep(300)
    }

It works fine printing

CoroutineExceptionHandler got java.lang.IllegalAccessException: Just testing

Process finished with exit code 0

Even if I replace GlobalScope with MainScope(), all still work fine.

However, if I use runBlocking as below.,

    @Test
    fun test() {
        val handler = CoroutineExceptionHandler { _, exception ->
            println("CoroutineExceptionHandler got $exception")
        }

        runBlocking(handler) {
            throw IllegalAccessException("Just testing")
        }

        Thread.sleep(300)
    }

It crashes

java.lang.IllegalAccessException: Just testing

    at com.example.coroutinerevise.CoroutineExperiment$test$1.invokeSuspend(CoroutineExperiment.kt:32)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at com.example.coroutinerevise.CoroutineExperiment.test(CoroutineExperiment.kt:31)

Why can't runBlocking have the given CoroutineExceptionHandler triggered?

Upvotes: 5

Views: 2093

Answers (1)

Stachu
Stachu

Reputation: 1724

it's not supported as per
https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/exception-handling.md#cancellation-and-exceptions

If a coroutine encounters an exception other than CancellationException, it cancels its parent with that exception. This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for structured concurrency. CoroutineExceptionHandler implementation is not used for child coroutines.

And runBlocking creates a child coroutine
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html

Runs a new coroutine and blocks the current thread interruptibly until its completion.

Something like this will work, but it's kind of ugly

    @Test
    fun test() {
        val handler = CoroutineExceptionHandler { _, exception ->
            println("CoroutineExceptionHandler got $exception")
        }
        try{
            runBlocking {
                throw InterruptedException("Just testing")
            }
        } catch(e:Exception){
            handler.handleException(GlobalScope.coroutineContext,e)
        }
        Thread.sleep(300)
    }

Upvotes: 2

Related Questions