Search code examples
kotlinkotlinx.coroutines

How Should cancelChildren work in Kotlin Coroutines?


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)


Solution

  • 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.