https://kotlinlang.org logo
Title
d

dimsuz

11/16/2021, 4:58 PM
I want to have a
supervisorScope
in which I want to do mutliple
launch
-es and allow each one to fail individually without cancelling other running ones. At the same time I'd want to install an exception handler on the
supervisorScope
itself to centrally handle everyting. But it seems that this can't be done, according to official documentation, i'll need to do
launch(handler)
every time. Do I understand this right? It's not problematic, but I'd rather avoid "forgetting" to pass "handler" to
launch
and have it automatically provided...
j

Joffrey

11/16/2021, 5:23 PM
It might not be possible to register an exception handler with the
supervisorScope
function, but you could define your supervisor scope manually like
CoroutineScope(SupervisorJob() + handler)
and then run your coroutines inside and cancel it when appropriate. It's not ideal but it does the job (pun intended)
🙂 1
c

Casey Brooks

11/16/2021, 5:23 PM
Rather than using
supervisorScope{}
function, you can build a
coroutineScope
that includes both your exception handler and a
SupervisorJob
. Something like this might help:
val newScope = originalCoroutineScope +
        uncaughtExceptionHandler +
        SupervisorJob(parent = originalCoroutineScope.coroutineContext[Job])

newScope.launch {
    // ...
}
newScope.launch {
    // ...
}
j

Joffrey

11/16/2021, 5:24 PM
I wonder why
coroutineScope
and
supervisorScope
don't provide a way to override the context 🤔
@Casey Brooks looks like we thought about the same thing 🙂
c

Casey Brooks

11/16/2021, 5:25 PM
You just got here a few seconds earlier 😉
I definitely don't fully understand the details, but looking at the implementation for
supervisorScope
, it looks like basically creates a new, completely isolated coroutine, unlike
withContext
and similar functions which augment the current coroutine.
And that makes sense to me, as the purpose of both
coroutineScope
and
supervisorScope
is to allow its children to fail without cancelling the entire coroutine. It is isolated from its parent so that you can manually control what happens when its children fail
j

Joffrey

11/16/2021, 5:37 PM
the purpose of both 
coroutineScope
 and 
supervisorScope
 is to allow its children to fail without cancelling the entire coroutine
This is only applicable to
supervisorScope
. The
coroutineScope
function fails if a child fails, and cancels all children in that case. Its purpose is mostly to do some parallel decomposition of work while suspending the current coroutine, I wouldn't say it's primarily about error handling. Even for
supervisorScope
I would say it's mostly about the same thing, but with the specific change in behaviour for error handling.
n

Nick Allen

11/16/2021, 5:41 PM
It doesn't need to be so complicated:
withContext(uncaughtExceptionHandler) {
    supervisorScope {
        ...
    }
}
c

Casey Brooks

11/16/2021, 5:41 PM
Right, that was unclear.
coroutineScope
cancels all of its own children, but failure/cancellation of itself or any of its children does not bubble up and cancel the parent coroutine automatically. Instead, it throws an exception which can be caught and handled manually, rather than just immediately cancelling the entire coroutine, parents, siblings, and all.
👍 1
d

dimsuz

11/16/2021, 5:41 PM
Oh, nice thank you all! I'm again porting stuff from Rx world and in general I want that very nice behaviour where I get to process all the errors in one place scoped by my separation of concerns. I.e. I don't want try/catch to be everywhere and also to be oftern forgotten.
Again to clarify. Am I getting this right that when using regular
CoroutineScope
, exception in any of
launch
-ed coroutines will cancel all the scope, and any other currently running coroutines, plus error hander for this scope will receive only one exception. But if I'll use a supervised scope (in any way you've suggested above), then failed
launch
wont bring everything down and my scope will be able to log/report-to-ui/whatever and then it can continue launching new coroutines in itself.
🙏 1
:yes: 2