Does anyone know how to tell when a channel has be...
# coroutines
a
Does anyone know how to tell when a channel has been closed while sending? The following hangs forever. I would like the suspend function to just return somehow if the send cannot complete.
Copy code
suspend fun main() = coroutineScope {
    val channel = Channel<Int>()
    
    //channel.close()
    
    launch {
        println("closing")
        channel.close()
    }
    
    channel.send(0) // hangs forever!!
    println("end")
}
https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS45LjAiLCJwbGF0Zm9ybSI6ImphdmEiLCJhcmdzIj[…]FubmVsLnNlbmQoMClcbiAgICBwcmludGxuKFwiZW5kXCIpXG59XG4ifQ==
I need a version of send that just throws or returns when the channel is closed.
s
I posted an answer to your StackOverflow question. I included a link to the docs for
send
, which I think does a good job of explaining what’s going on here.
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. All elements sent over the channel are delivered in first-in first-out order. The sent element will be delivered to receivers before the close token.
If you want to immediately drop all elements from the channel and cancel any attempts to send new elements, you should call
cancel
instead of
close
. The close function is for use by the sender, and the cancel function is for use by the receiver.
a
Thank you! You definitely answered the specific question I asked but unfortunately it doesn’t solve the problem I’m having. After some digging, I’ve narrowed it down to strange behavior coming from
consumeAsFlow
. I accepted you answer though and posted a different question.
TL;DR consumeAsFlow doesn’t seem to promptly cancel the underlying Channel when cancelled. Here’s the full post: https://stackoverflow.com/questions/76923816/consumeasflow-doesnt-promptly-cancel-the-underlying-channel-when-cancelled
s
consumeAsFlow
just creates the flow, it doesn't run it. You need to call a terminal function like
collect
(or
launchIn
) to have the flow actually execute.
a
oh whoops brainfart 😅. So the playground and question were wrong but I am definitely calling collect in my overall code.
I’ll close the question and keep digging 😐
Turns out both of these were red herrings. 🙃 Thanks for the help @Sam!