Manuel Pérez Alcolea
04/23/2023, 10:51 PMJob state this:
Creates a job object in an active state. A failure of any child of this job immediately causes this job to fail, too, and cancels the rest of its children.this makes me think that if I have 2 jobs
a and b `launch`ed from the CoroutineScope of Junk, and said scope's context is just a Job()...
class Junk : CoroutineScope {
    override val coroutineContext: CoroutineContext = Job()
}
// ...
val junk = Junk()
val a = junk.launch { /*...*/ }
val b = junk.launch { /*...*/ }
b.cancel()
joinAll(a, b)
...then cancelling b should cancel a and viceversa. But that doesn't happen. b gets cancelled quietly, and a does its thing (the full version of this snippet has delay(1000); println("hello from...") in each coroutine)
If "failing" is not cancelling, then... it's to have an unhandled exception? (If that's the case I don't understand the practical difference between a Job and a SupervisorJob, but one thing at a time)Adam S
04/23/2023, 11:21 PMA coroutine that threw CancellationException is considered to be cancelled normally. If a cancellation cause is a different exception type, then the job is considered to have failed.2.
launch {} means a new Job() is created - with a parent based on the current coroutine context.
https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#children-of-a-coroutine
When a coroutine is launched in theof another coroutine, it inherits its context viaCoroutineScopeand theCoroutineScope.coroutineContextof the new coroutine becomes a child of the parent coroutine’s job.Job
Manuel Pérez Alcolea
04/23/2023, 11:37 PMlaunch and other functions (all of them?) to create coroutines always their own Job . Also I realized I'm just dumb and while writing a snippet to show you what I didn't get about Job vs SupervisorJob, I ended up understanding the difference. Which is exactly what's explained in the documentation, but my job a was completing successfully before `b`'s exception would reach its parent.Manuel Pérez Alcolea
04/23/2023, 11:44 PMval a = junk.launch {
    delay(1000)
    println("Hello from a")
}
val b = junk.launch {
    delay(500)
    throw Exception()
    println("Hello from b")
}
joinAll(a, b)
class Junk : CoroutineScope {
    override val coroutineContext: CoroutineContext = Job() + CoroutineExceptionHandler {_, _ -> println("A coroutine failed")}
}
So, this makes both `junk`'s and `a`'s jobs fail, as intended. Replacing `Junk`'s for `SupervisorJob`:
class Junk : CoroutineScope {
    override val coroutineContext: CoroutineContext = SupervisorJob() + CoroutineExceptionHandler {_, _ -> println("Falló")}
}
gives a different result, where only b fails
Ok thanks for your time, testing concurrency is hard.Adam S
04/24/2023, 8:36 AM