https://kotlinlang.org logo
Title
b

bbaldino

12/01/2020, 6:33 PM
If I do:
val t = scope.async { ... }
val u = scope.async { ... }
try {
    select<Unit> {
        t.onAwait { ... }
        u.onAwait { ... }
    }
} catch (c: CancellationException) {
    ...
} catch (t: Throwable) {
   ...
}
where
scope
is not cancelled anywhere and one of the
t
,
u
tasks throws an exception, should I always be able to catch the exception that was thrown in my block? I'm seeing that most of the time I get the exception thrown by
t
or
u
, but sometimes I get a
CancellationException
wrapping the exception thrown by
t
or
u
and I'm trying to figure out if this is to be expected when using
select
or if I'm doing something wrong.
b

bezrukov

12/01/2020, 6:37 PM
Most likely you use Job in your
scope
that means if any of your async blocks fails, another will be cancelled as well. If you will switch to SupervisorJob another async won't be cancelled
b

bbaldino

12/01/2020, 6:38 PM
In this case I'm only using it for these 2 tasks. I made up a little example here: https://pl.kotl.in/h0f2ojO-z
And I'm fine with everything being cancelled--that's what I want--but I want to get the real exception if a task throws, not
CancellationException
b

bezrukov

12/01/2020, 6:44 PM
If you switch to
private val scope = CoroutineScope(SupervisorJob()+CoroutineName("FileRecordingService"))
you will catch only error from t
b

bbaldino

12/01/2020, 6:45 PM
And just cancel the other task manually? I do want everything to cancel if anything throws, which is why I didn't use SupervisorJob.
Is it some kind of race, basically?
b

bezrukov

12/01/2020, 6:46 PM
Anyway you have to cancel it, if T ends with no exception.
b

bbaldino

12/01/2020, 6:46 PM
It will be cancelled automatically if the other one throws though (without supervisor scope)
Oh, sorry, I misunderstood what you said. Yes that's true but doesn't apply in my case: these tasks always continue to run until cancelled from higher up or throwing an exception.
b

bezrukov

12/01/2020, 7:21 PM
then you can simply use
try {
  coroutineScope {
    async { // t code }
    async { // u code }
  }
} catch (e: ...) {
}
it should work as you expected
b

bbaldino

12/01/2020, 7:24 PM
Great, I'll give that a try. Thanks!
b

bezrukov

12/01/2020, 7:24 PM
b

bbaldino

12/01/2020, 7:25 PM
That code looks the same as the one I pasted, might have to generate a new link to see your changes?
b

bezrukov

12/01/2020, 7:25 PM
open it in incognito window or force reload
playground aggressively uses the cache
b

bbaldino

12/01/2020, 7:26 PM
Cool, got it.
b

bezrukov

12/01/2020, 7:27 PM
but anyway regenerated https://pl.kotl.in/zL5IA3N1V
b

bbaldino

12/01/2020, 7:27 PM
Is it possible to get the
coroutineScope
behavior (wait for all children to finish) within the scope of an explicit
CoroutineScope
? (e.g. the
scope
member of that class)
b

bezrukov

12/01/2020, 7:28 PM
pull the job from this scope (scope.coroutineContext.job on latest version or scope.coroutineContext[Job] on older) and call join() on it
b

bbaldino

12/01/2020, 7:29 PM
Pull the job from the
coroutineScope
scope and join it in the
scope
scope?
b

bezrukov

12/01/2020, 7:29 PM
just call scope.coroutineContext.job.join() from any suspend fun
b

bbaldino

12/01/2020, 7:42 PM
I ended up doing this, maybe there's a better way:
scope.launch {
    try {
        coroutineScope {
           launch { ... }
           launch { ... }
        }
    } catch (...) {
    }
}.join()
I wanted it to be run as a child of
scope
so that I can have a
stop
method in the class which can call
cancel
on
scope
I found it did work out better to let the caller manage the job by launching it on its own, so no need for the scope member variable. Thanks a lot for the help @bezrukov!
b

bezrukov

12/01/2020, 9:19 PM
🤞 yep, this is an idiomatic way to do this. That means you typically have to write regular suspend functions that use implicit coroutine context (propagated from the caller) instead of using CoroutineScope directly. Then caller can decide how/when to launch it and how/when to cancel it
b

bbaldino

12/01/2020, 9:20 PM
👍