Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancel all scope children coroutines based on any child result

Assume there are two suspend function which return a boolean. They need to be launched in parallel but cancel each other if false is returned.

suspend fun task1(): Boolean {
    delay(10000)
    return true
}
suspend fun task2(): Boolean {
    return false
}

The tasks can be run in parallel by launching them with async and cancel each other by throwing CancellationException inside a coroutineScope as shown below.

coroutineScope {
    setOf(
        async { task1() },
        async { task2() }
    ).forEach{ d ->
        d.await().also {
            if (it == false)
                throw CancellationException()
        }
    }
}

The problem is that the results are processed in the order of await calls, i.e. task2 result is processed only after task1 result and hence task2 won't ever cancel task1. It is possible to re-arrange this to let task2 cancel task1?

like image 647
yaugenka Avatar asked Nov 27 '25 12:11

yaugenka


1 Answers

If you need to wait for more results at once in a parallel manner (instead of the sequential manner where your problem lies) you can use the select clause, like this:

coroutineScope {
        val tasks = setOf(
                async { task1() },
                async { task2() }
        )
        
        select {
            tasks.forEach {
                it.onAwait { finishedSuccessfully ->
                    if (!finishedSuccessfully)
                        tasks.forEach { task -> task.cancel() }
                }
            }
        }
    }
like image 163
Horațiu Udrea Avatar answered Nov 30 '25 06:11

Horațiu Udrea



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!