After updating coroutines (android) from 1.2.1 to ...
# coroutines
m
After updating coroutines (android) from 1.2.1 to 1.3.0 (same if 1.3.1) I’m getting this crash:
"kotlinx.coroutines.channels.ClosedSendChannelException: Channel was closed"
when calling
SendChannel.send
(note: I’m using
produce
to build the channel). I’ve isolated the cause to be this upgrade. I couldn’t find anything relevant in the release notes: https://github.com/Kotlin/kotlinx.coroutines/releases . Any tips on how to investigate what could be causing this, please?
o
what does your
produce
look like?
l
Use
cancel()
instead of
close()
.
👍 1
m
@louiscad I’m currently using
close()
because I have a reference to the channel (and I think there is no
cancel()
on
Channel
). Does this mean instead I need to hold onto a reference of the
Job
corresponding to the
Channel
instead (in order to cancel)?
o
there is a
cancel
on Channel
specifically, it is inherited from
ReceiveChannel
m
@octylFractal ah yes, sorry I was looking at
SendChannel
@louiscad thanks very much, using
cancel()
instead of
close()
fixed the problem. Is there a reference to this behavior change in the docs somewhere?
l
@Mark I think your best source is the documentation of both these functions. I learned about the difference between them the hard way after half an afternoon of debugging. You can submit an issue on GitHub to ask for it to be warned about in the guide/doc, and in the
close
function KDoc.
o
yes, this is not really a behavior change --
close
is for the sending side, indicating it is done sending,
cancel
is for the receiving side.
essentially, a
close
should never be followed by a
send
, because the sender declared the channel to be closed (and similar for
cancel
& receiver)
👍 1
m
Thanks @octylFractal that makes sense not to call
close()
from the receiver. I was actually calling it from a class managing the channels (when the channel becomes obsolete due to external conditions). So now I know
cancel()
is the correct way 🙏 But yes, a thorough reading of the docs is probably a wise investment of time!
d
@Mark there's a major difference between cancel and close. Cancel causes elements not yet received to be dropped. Close doesn't.
The correct thing to do is to call close, not cancel. Moreover, produce will invoke close automatically when the coroutine completes for any reason.
m
@Dico if I want to discard a channel (from the receiver side) surely I want the not-yet-received elements to be dropped?
v
The main motivation here is that attempt to send to a closed channel is either a close race (then channel should be cancelled, not closed) or a programmatic error. In the latter case, it should not be ignored, thus it became ISE instead of CE
👍 1