Safe async in a given scope

有些话、适合烂在心里 提交于 2020-01-24 09:49:07

问题


I want to start an async coroutine with a suspending function in a given parent CoroutineScope, to produce a Deferred that might then be used from any coroutine in that scope.

I would like its job to be cancelled if the parent's job is cancelled, but if the suspending function throws an exception, I need that captured in the resulting Deferred without cancelling sibling jobs in the parent scope.

The way I'm doing it works fine, but I'm wondering if there's a simpler, more idomatic way than this:

fun <T> callIt(scope: CoroutineScope, block: suspend () -> T) : Deferred<T> {
    val result = CompletableDeferred<T>()
    scope.launch {
        try {
            result.complete(block())
        } catch (e: Throwable) {
            result.completeExceptionally(e)
        }
    }
    return result
}

I like that the handling of exceptions from the suspending block is obviously what I want, but I'm not too happy about building an async out of launch

Things that don't work:

  • An async job with an exception handler. async catches its exceptions, but the job still fails and cancels its parent. As @Rene commented: The documentation of async says: " it cancels the parent job (or outer scope) on failure to enforce structured concurrency paradigm.".

回答1:


You can do it without a CompletableDeferred. You need to create an SupervisorJob and let the job from the CoroutineScope be the parent of the new job. If the scope is cancelled the async-coroutine is cancelled as well. But no exception inside the async-coroutine will cancel the parent scope.

Because of an open issue https://github.com/Kotlin/kotlinx.coroutines/issues/1578 we need to explicitly complete the SupervisorJob.

fun <T> callIt(scope: CoroutineScope, block: suspend () -> T): Deferred<T> {
    val supervisorJob = SupervisorJob(scope.coroutineContext[Job])
    val deferred = scope.async(supervisorJob) {
        block()
    }
    deferred.invokeOnCompletion {
        supervisorJob.complete()
    }
    return deferred
}


来源:https://stackoverflow.com/questions/58229357/safe-async-in-a-given-scope

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!