https://kotlinlang.org logo
Title
a

Afzal Najam

02/04/2021, 5:03 PM
So I just tried this in a Kotlin/JVM project, and it didn't work as I thought it would. If I create a scope like this, and one of its children jobs had an exception, the parent cancels and no other coroutines can be launched:
val parentScope = CoroutineScope(Dispatchers.Default + Job() + exceptionHandler)
But if I create it like this, and one of its children jobs had an exception, siblings didn't fail and other coroutines were able to launch just fine:
val parentScope = MyScope()
Where
MyScope
is:
class MyScope: CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Default + Job() + exceptionHandler
}
I thought that both `parentScope`s would behave exactly the same. Am I missing something? Here's a gist: https://gist.github.com/AfzalivE/3bfe168e879ba8b97ad62292217b0491
l

louiscad

02/04/2021, 5:18 PM
The right way to avoid this problem is catching the exceptions where they happen. Otherwise, they will cancel the scope.
i

Ivan Pavlov

02/04/2021, 8:25 PM
a

Afzal Najam

02/04/2021, 8:27 PM
@Ivan Pavlov, MyScope is already behaving like a supervisor here, which is why I'm confused. @louiscad That would be ideal. I think we're just going with letting the app crash so that any underlying issues can surface but I'm interested in understanding what's going on here. 🙂
i

Ivan Pavlov

02/04/2021, 8:38 PM
Have you tried to change Job() for SupervisorJob() in your case?
a

Afzal Najam

02/04/2021, 8:39 PM
Yeah in this scenario, I tried switching and it worked the same as it does with MyScope. Why wouldn't the normal Job in MyScope not cancel when its children throw an exception though?
l

louiscad

02/04/2021, 8:40 PM
I already answered that.
a

Afzal Najam

02/04/2021, 8:40 PM
@louiscad In the code above, MyScope isn't being cancelled.
l

louiscad

02/04/2021, 8:42 PM
Let me clarify this further: by design, any uncaught exception (that is not a
CancellationException
) reaching a coroutine launcher will cancel the
Job
in its scope, and there's no going back from a cancelled
Job
instance.
Great learning resource:

https://youtu.be/Mj5P47F6nJg

a

Afzal Najam

02/04/2021, 8:45 PM
Sorry but maybe I'm not being clear. I'm not trying to go back from a cancelled job. I'm trying to ask why MyScope isn't getting cancelled when a job in its scope is throwing an exception. As you can see, the
parentScope
created using the CoroutineScope function does get cancelled when a job in its scope throw an exception. Am I missing something?
l

louiscad

02/04/2021, 8:46 PM
It's because you have an exception handler
i

Ivan Pavlov

02/04/2021, 8:48 PM
Probably MyScope produces new context each time because of
get
?
l

louiscad

02/04/2021, 8:48 PM
I'm not using them at all, preferring plain try/catch (while always rethrowing or not catching
CancellationException
). I think that route would work fine for you as well.
Ah yes, great catch! It should use a backing field, not a getter.
a

Afzal Najam

02/04/2021, 9:00 PM
@Ivan Pavlov Thank you! That explains everything! So it was my fault in the end. @louiscad I think I agree to not use them, depends on the app. If not continuing other operations is more important than the task within the coroutine, then it makes sense to try/catch and crash otherwise. But say for a VPN app where keeping the VPN connection on is the most important thing, you would still want to avoid crashing in unknown states and just log the exception in the crash reporting tool.
l

louiscad

02/04/2021, 9:06 PM
Yep, totally agree with your take on crashing or not.