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.
asynccatches its exceptions, but the job still fails and cancels its parent. As @Rene commented: The documentation ofasyncsays: " it cancels the parent job (or outer scope) on failure to enforce structured concurrency paradigm.".