-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Universal API for use of closeable resources with coroutines #1191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
More considerations:
where |
Then the same API for channels:
where a shortcut can be also made:
|
@elizarov Can |
@fvasco Good catch. |
Special method can works for typealias Disposer<T> =suspend (T) -> Unit
channel.send(r, Resource::close) These consideration should be applicable to Should this behaviour be a part of interface DisposeHandler : CoroutineContext.Element {
/**
* Dispose [resource] and returns `true`, `false` otherwise
*/
suspend fun dispose(resource: Any): Boolean
}
object CloseableDisposeHandler : DisposeHandler, CoroutineContext.Key<CloseableDisposeHandler> {
override suspend fun dispose(resource: Any): Boolean {
return if (resource is Closeable) {
// the Dispatcher should be IO, the same of withContext
resource.close()
true
} else false
}
override val key: CoroutineContext.Key<*> get() = CloseableDisposeHandler
}
suspend fun main() {
coroutineScope {
val tempFile = withContext(Dispatchers.IO + CloseableDisposeHandler) {
createTempFile()
}
}
} Should
|
Adding disposers to the context and then selecting them based on the runtime "instanceof" checks seems to be a dangerous road to be. For files, in particular, a dedicated scoped API seems to work better:
So this solution is othogonal to coroutines and works great with |
Would there still be no guarantee as to where (thread speaking) the close lambda would be executed, and would it still be a blocking lambda, with no suspension points support? |
After some discussion, we've decided that "universal" wrapper API like a In light of #1813 we decided for a more modest replacement. See #1936. |
For background of the problem see #1044. There we've introduced a special API for
CancellableContinuation
(resume(r) { r.close() }
) so that you can resume with a "closeable resource" that would be atomically close if the continuation is cancelled. However, there are other APIs in coroutines that can potentially lose closeable resource on cancellation:async { ... }
may produce a result but then get cancelled in a race, so that the resulting resource is lost (not closed)withContext/withTimeout/coroutineScope/etc
may return a resource, but get cancelled on return path.So the proposal is to add a universal API for closeable resources in form of a wrapper class that is used like this:
Resource(v) { v.close() }
So, for example, that if how you can use it with
async
:Now if
deferred
is cancelled, the resource is closed. You can use it like:Additional considerations
We may also want to introduce some interface with
close
ordispose
function that does the similar trick for classes implementing this interface (and makeResource
implement it). The name of this interface is hard to come by with, though.Maybe this is a wrong approach altogether. Maybe we shall look at scoped resource management.
The text was updated successfully, but these errors were encountered: