kotlinx.coroutines
kotlinx.coroutines copied to clipboard
flatMapLatest + combine + first leads to execution while cancelled
Describe the bug
Firstly, it's possible this is expected behavior but it certainly doesn't seem that way.
We have a flow that we collect using first(). This flow is a combination of multiple upstream flows but they all emit their items synchronously. The downstream flow limits the number of emissions to a single element then uses awaitCompletion() to avoid terminating the flow. This is the flow we call first() on.
Under some circumstances, we are seeing the first() call resuming after the scope has been cancelled which is causing a crash for us.
If either the flatMapLatest or combine is removed, the code behaves as expected, although first() never resumes.
I know there are no real guarantees that code won't be running while canceled. But there are few things that makes me think that this doesn't apply in this case:
- There is no non-cooperative suspension as far as I know.
- Only a single thread is involved.
Provide a Reproducer This reproduces it on an Android device, but it's possible it can reproed on the JVM too.
// This must be run on the main thread
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
println("Before launch")
scope.launch {
flowOf(listOf(1, 2, 3))
.flatMapLatest { numbers ->
combine(numbers.map { flowOf(it) }) { it.sum() }
}
.onEach { println("Got item") }
.first()
println("After first, scope is active: ${scope.isActive}")
}
println("After launch")
scope.cancel()
I expect this to print:
Before launch
Got item
After first, scope is active: true
After launch
Instead I'm seeing this:
Before launch
Got item
After launch
After first, scope is active: false
Could not reproduce with coroutines 1.7.3 using Android instrumented tests. The output for me is:
Before launch
Got item
After launch
Due to cancellation, the "After first" println didn't execute.
Yes, that's right. It does not repro in an instrumented test for us either. But it does when you put that code in Activity.onCreate it does. I'll attach a complete project.
Here is a complete example. Run it and see the output in logcat. Coroutinesbug.zip
Ok, reproduced.
@dkhalanskyjb Can you remove the "waiting for clarification" label so it doesn't get auto closed?