ralf
08/28/2023, 9:45 PMkotlinx.coroutines.test.UncompletedCoroutinesError: After waiting for 10s, the test coroutine is not completing, there were active child jobs: [UndispatchedCoroutine{Active}@337aeb49]
We enabled DebugProbes
to track down the coroutine running and it’s:
Coroutine "coroutine#10":StandaloneCoroutine{Cancelled}@475d618b, state: RUNNING (Last suspension stacktrace, not an actual stacktrace)
at app.cash.turbine.ChannelKt$withWallclockTimeout$2$timeoutJob$1.invokeSuspend(channel.kt:114)
at _COROUTINE._CREATION._(CoroutineDebugging.kt:34)
This points us to this line:
val timeoutJob = GlobalScope.launch(Dispatchers.Default) { delay(timeout) }
It seems like this job is scheduled and cancelled, but then keeps running. How can a coroutine be cancelled and running at the same time, when it only executes a single suspending block? Any advice? Could this be potentially a bug in the implementation?franztesca
08/29/2023, 4:03 AMsuspend fun example() {
while (true) {
Thread.sleep(1000)
}
}
is not cancellable and will run forever no matter whether you cancel the coroutine.
Plus, even when cooperative, cancellation is asynchronous: from the moment when you cancel to the moment when it stops executing, some time may pass. You should leverage structured concurrency and avoid GlobalScope, generally speakingralf
08/29/2023, 4:36 AMdelay(..)
is cooperative and should not keep running. The tests in question usually execute within a few milliseconds. 10 seconds should be more than plenty to cancel the coroutine.Sam
08/29/2023, 7:57 AM