Hi, I stumbled upon this behaviour. Is this really...
# coroutines
a
Hi, I stumbled upon this behaviour. Is this really a bug or am I missing something? https://github.com/Kotlin/kotlinx.coroutines/issues/3757
t
This looks like expected (but confusing) behavior. the
cancel()
is called on a
CoroutineScope
. The
this
being called on is the surrounding
launch
. When this happens the flow is going to stop collecting, but the other launched coroutine scope is unaffected. The flow will stop collecting and call close on the channel, but according to the docs
Copy code
Closing a channel after this function has suspended does not cause this suspended send invocation to abort, because closing a channel is conceptually like sending a special "close token" over this channel.
When you call
coroutineScope { cancel() }
what actually is happening is you are using the
suspend
block inside of collect, creating a coroutine scope, and calling cancel on that. That scope cancellation will then propagate up the suspending function calls. To prove this, add a
delay(100)
between the channel send, and use the cancel() version. You should see your expected error
All of that said, you should avoid passing channels around, esp ones from channelFlow builders like this.
TLDR: 2nd send suspends before cancellation due to
cancel()
being called on the launch's coroutinescope. Using
coroutineScope{cancel()}
cancels the suspending function immediately so the second send doesn't get to suspend
a
It seems that send gets suspended in both cases: https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS44LjIxIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncy[…]gpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSJ9 I see it as following: in case with
coroutineScope{cancel()}
ProducerCoroutine gets canceled, which leads to
channel.cancel()
call which wakens up suspended
channel.send()
in case with
cancel()
call,
launch
coroutine gets canceled, which then cancels all its children, in this case ProducerCoroutine, but it calls
channel.close()
instead, which has no effect on suspended
channel.send()
t