There’s a safe way to return a resource (closable/disposable object) from a coroutine without potentially leaking it?
There’s a solution for undelivered elements like we have for Channel?
There’s a safe way to return a resource (closable/disposable object) from a coroutine without potentially leaking it?
There’s a solution for undelivered elements like we have for Channel?
Leaking meaning that the caller doesn’t close it?
Well you have to hope the caller closes it, same thing you do when you return it from a function. Is there something special about coroutines?
No, leaking meaning the reference to the resource object is not lost by the coroutine library. I want a safely way to pass the ownership of an object between two entities.
class SomeCloseableObject : AutoCloseable {
//...
void close() throws Exception {
//...
}
}
suspend fun produceSomeCloseableObject(): SomeCloseableObject {
return SomeCloseableObject()
}
suspend fun someClient() {
// The issue is here, no one promise that the reference will be passed to the client. For example
// if the scope is cancelled before the suspend function returned.
val closeableResource = produceSomeCloseableObject()
//...
closeableResource.close()
}
This is exactly why cancellations in coroutines are cooperative and handled by exceptions. Coroutines don’t really differ in that matter from non-coroutine code. We just use standard tools for handling resource cleanups:
produceSomeCloseableObject().use { closeableResource ->
...
}
Unfortunately we cannot rely on this, we can still lost the reference/resource. See the following issue Universal API for use of closeable resources with coroutines · Issue #1191 · Kotlin/kotlinx.coroutines · GitHub
I know in some cases we may leak a resource due to cancellation, but it is unclear what case exactly do you mean, because “return from coroutine” is pretty enigmatic. If you mean returning from a suspend function, then I believe there is no problem with that. If you mean returning from async{}
, withContext()
, coroutineScope()
, withTimeout()
, etc. then I think there is a problem. It was mentioned here: Cancellation and timeouts | Kotlin
Example provided by you was about returning from a suspend function and for this case I believe (but I may be wrong) simple use()
is safe.