Skip to content

Dispatcher failures may leave coroutines uncompleted #4209

Open
@dkhalanskyjb

Description

Describe the bug

During the review of #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.

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