According to the docs cancelChildren should cancel a coroutine's children but leave the parent unaffected ("the state of this job itself is not affected.") However if I have code like
val outer = launch {
try {
launch (coroutineContext) {
try {
// work here
} catch (ex: Exception) {
println("In inner catch")
} finally {
println("In inner finally")
}
}
delay(5000) // so the outer job is running when I cancel it
} catch (ex: CancellationException) {
println("In outer catch")
} finally {
println("In outer finally")
}
}
delay(100) // give it a chance to run
outer.cancelChildren()
Then I see the following
In inner catch
In inner finally
In outer catch
In outer finally
Why is the 'outer' job getting cancelled?
This is the exact same behaviour I get if I call outer.cancel (but that I expect)
Your delay(5000)
in the outer coroutine is cancellable and thus is affected by outer.cancelChildren()
. It throws the CancellationException
seen in the outer try
. The cancelChildren
function does not cancel the outer job, which can be made obvious by checking outer.isCancelled
after the call.
If the delay
invocation is removed from the code, it prints the expected result. Note that coroutines wait for their children anyway, delaying is not necessary:
A parent coroutine always waits for completion of all its children. Parent does not have to explicitly track all the children it launches and it does not have to use Job.join to wait for them at the end.