Return a resource from a coroutines without leaking it

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?

https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html

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

1 Like

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.

1 Like