https://kotlinlang.org logo
#coroutines
Title
# coroutines
m

Marc Knaup

03/21/2019, 3:35 PM
Are `ReceiveChannel`s closed automatically somehow if you for-loop over them even if you
break
at some point?
s

streetsofboston

03/21/2019, 3:39 PM
Not sure, but I don’t think so. A for-loop ends when the ReceiveChannel is closed by some other code. Just breaking out of it, won’t close it automatically,
m

Marc Knaup

03/21/2019, 3:39 PM
That's really easy to miss then 😮 Esp. when migrating code to coroutines 😕
s

streetsofboston

03/21/2019, 3:43 PM
A channel, in this regard, is like a InputStream in Java… they don’t close automatically
You could create a Channel inside a
launch
and tie the CoroutineScope of the
launch
to closing the channel by implementing the
Job.invokeOnCompletion
on the job returned by the call to
launch
. Close the channel in the invokeOnCompletion. Then this Channel could be given to the consumer as a ReceiveChannel
m

Marc Knaup

03/21/2019, 3:52 PM
Hmm, I don't think that will work in my case 🤔 I want to turn MongoDB's async iterable into something that's close in the coroutine world: https://github.com/fluidsonic/fluid-mongo/blob/master/sources/Utility.kt#L38 In MongoDB sync you can just iterate over stuff without closing anything (I have no idea how that's support to work). My current implementation is broken because I tried making my
MongoIterable
a
ReceiveChannel
which doesn't make sense I guess 🙄
s

streetsofboston

03/21/2019, 3:59 PM
Autoclose doesn’t really exist like that in Java or Kotlin. In Kotlin, you could use the
use
function to mimic that behavior somewhere as long as you make your new iterable ‘closeable’ as well.
But if folks forget to use/call
use
, the channel won’t be closed…..
m

Marc Knaup

03/21/2019, 4:01 PM
Yeah that sucks 😕 Timeout-based closing of channels may be a workaround but isn't nice.
s

streetsofboston

03/21/2019, 4:11 PM
you could call
someChannel.consume { val channel = this }
on your channel first as well.
consume
makes sure its receiver Channel is closed(canceled) when your code returns from the
consume
call.
m

Marc Knaup

03/21/2019, 4:13 PM
Yeah but every user of the library has to do that for every database query then which is what I'd like to avoid.
s

streetsofboston

03/21/2019, 4:43 PM
The code has to know when the user of the Channel is done with it. The user needs to call some method on that Channel to indicate that. A
break
statement doesn’t do that. This would mean that whichever solution you create, the user of the channel has to do something extra somewhere to properly close the channel. You could have the creator of the Channel close the channel when it is done with it or when the creator goes out of (Coroutine)scope. But that may not work for you use-cases….
r

r4zzz4k

03/21/2019, 4:57 PM
And, like, user code consuming the channel would think of the need to close it anyway, it's not that your library is the only thing which makes users to manage resources they open 🙂 So I wouldn't worry about that too much.
m

Marc Knaup

03/21/2019, 5:13 PM
The thing is that in the synchronous API of MongoDB Java Driver you don't need to worry about closing the queries. Just iterate over it, maybe break, whatever. The coroutine one was supposed to work exactly the same way, just with
suspend
added. You don't need to change anything else. But that's not possible without leaking channels or having potentially unexpected channel lifetimes (timeout, scoped, etc.).
s

streetsofboston

03/21/2019, 5:17 PM
How does mongo know when a user of the query/cursor/iterable is done with it? Just breaking out of a loop that knows nothing about queries/cursors… not sure how that would work.
m

Marc Knaup

03/21/2019, 5:59 PM
I've also been wondering. Closing resources is not a thing with their driver. My guess is that they simply time-out everything which isn't fully consumed. Also they do requests in batches internally, so maybe there aren't even any dangling resources when not closing the query if the server is stateless somehow.
2 Views