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 viaCoroutineScope
and theCoroutineScope.coroutineContext
of 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