So I just tried this in a Kotlin/JVM project, and ...
# coroutines
a
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:
Copy code
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
The right way to avoid this problem is catching the exceptions where they happen. Otherwise, they will cancel the scope.
i
a
@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
Have you tried to change Job() for SupervisorJob() in your case?
a
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
I already answered that.
a
@louiscad In the code above, MyScope isn't being cancelled.
l
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
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
It's because you have an exception handler
i
Probably MyScope produces new context each time because of
get
?
l
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
@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
Yep, totally agree with your take on crashing or not.