Kotlin / kotlinx.coroutines

Library support for Kotlin coroutines
Apache License 2.0
13.06k stars 1.85k forks source link

Dispatcher failures may leave coroutines uncompleted #4209

Open dkhalanskyjb opened 2 months ago

dkhalanskyjb commented 2 months ago

Describe the bug

During the review of https://github.com/Kotlin/kotlinx.coroutines/pull/4181, it became evident that we don't properly handle failures in coroutine dispatchers, and this can surface in ways other than just strange-looking exceptions.

Provide a Reproducer

val dispatcher = newSingleThreadContext("unreliable friend")
runTest {
    launch(dispatcher, start = CoroutineStart.UNDISPATCHED) {
        try {
            println("This code runs...")
            suspendCancellableCoroutine<Int> { cont ->
                // we launch a separate thread and wait a bit,
                // because we want the coroutine to actually suspend
                // and go through a dispatch.
                launch(Dispatchers.Default) {
                    delay(100)
                    // close the dispatcher, now it will throw on `dispatch`
                    dispatcher.close()
                    // try dispatching the coroutine
                    cont.resume(3)
                }
            }
        } catch (e: Throwable) {
            println("Caught $e")
            throw e
        } finally {
            println("... therefore, this code must run.")
        }
    }
}

This code will hang after printing This code runs..., as the launched coroutine never finishes.

dkhalanskyjb commented 2 months ago

It's unclear what to do in this scenario, though. Here are some options: