-
Notifications
You must be signed in to change notification settings - Fork 161
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
Getting errored/closed reader, Auto-releasing reader, Forcible cancel() on a stream #297
Comments
Thanks for bringing these up. I was actually just preparing a follow-up commit to the PR to propose a solution for these issues :). It is nice to have a new issue to discuss though.
Great justifications, agreed.
Yes, I agree it is not as necessary anymore. We can probably remove it. The change in behavior between auto-release and manual release only impacts a few minor cases. But on the other hand, I am not sure what the downsides of auto-release are, if any. So maybe we should more carefully consider what the changes in behavior are and which result we would prefer.
I am less sure about this one. I am having a hard time with use cases though. I will have to think on it harder. Another question: Should we allow cancellation of a locked stream?The PR #296 does allow this. It is kind of a violation of the authority principles getReader() is based around. However, without it, you can get in trouble by setting up a pipe chain without having any way to shut it down. I think the proper solution to this is to change If we have this in place then we can remove cancellation of locked streams and keep the authority with the reader. We will still have |
See discussion in #297. This commit implements the following changes: - Allow acquiring readers for closed or errored streams; they simply act closed or errored. - Stop auto-releasing readers when streams close/error. - Disallow canceling a stream that is locked to a reader (you should use the reader cancel). - Piping from a closed or errored stream will close or abort the destination stream, instead of immediately failing the pipe.
I added bb47488 to the pull request which address much of these. I will do another follow-up commit changing the pipeTo return value. |
See discussion in #297. pipeTo now returns a { finished, unpipe() } object, instead of just a promise.
Regarding auto-release: there are very very few differences in behavior that you can discern without inspecting The only difference I can find is that if you write "bad" reader-using code that doesn't release the reader when it finishes with it, nobody will be able to get any more readers, even though those readers will always just be closed/error. (Actually, the readableStreamToArray function in the pull request is an example of such bad code: it will release upon successful close, but not if the stream errors.) So, I think it would be better to keep auto-release. |
Mainly from Fetch API point of view... Regarding auto-release: We had a long discussion about Body.bodyUsed which is summalized at https://github.com/tyoshino/streams_integration/blob/master/FetchBodyPrecondition.md. In the discussion, people tended to like a flag which would never be released after locked (e.g. new Request, cache.put()). If it is generally true, leaving an option for a user to "not release" might be good. Regarding forcible cancel:
Not having forcible cancel means that any consumer should have a cancel method, and it should be an object, not a function (i.e. text() is not a good API). (Of course, we could have cancel() on Request or Response, but it looks a bad sign to me.) |
Yutaka: Good point. To address an issue the cancellation issue with pipeTo(), basically we need to do the same for the methods (text(), json(), ...) on the Body. It's sad but we cannot adopt Hmm, will it be better if we provide not forcible cancel() but forcible releaseLock() on the stream? |
I think it is not so bad to not support cancellation of On the other hand the forcible releaseLock() is an interesting idea... Kind of counterintuitive, but I will think about it more. |
I see. Should we also address pipeTo() cancellation issue by the cancellable promises?
or
Wouldn't the latter be implemented adopting the revealing constructor pattern? |
Oh wow, good point, I hadn't thought of that. That would make more sense. Maybe we should leave pipes uncancellable until cancellable promises land. That would give me more motivation to work on cancellable promises, haha -_-. The latter is pretty similar to revealing constructor, yeah. Although it would tie into a more general cancelable promise framework. |
The canceller idea looks good to me. |
We just had more discussion about cancelling fetch(). In #297 (comment), Yutaka meant that we should have some method to stop receiving HTTP response body. It could be any of res.cancel(), res.body.cancel() and reader.cancel(). He thought having three points is bad and wondered what we should have. Sorry, I forgot but I'm also fine with your (Domenic's) canceller approach. Regarding the Fetch API, we also need a method to terminate the fetch algorithm while the promise is not yet fulfilled (response headers are not yet available). So, my gut feeling is that we shouldn't have two termination methods but only one that is available from the time we start the fetch algorithm. Yutaka and I also discussed this a little. So, I like the canceller revealing approach. My preference on |
Right, there is a lot of discussion about how to do fetch cancellation, I think in the service worker repo. I think it is OK to (eventually) have multiple possibilities as long as they all related together. E.g. maybe Hmm. But if we allow |
Related issue at the Fetch API issue trakcer: whatwg/fetch#20 |
OK, quick in-person huddle yielded the following proposal.
This makes a lot of sense to me. Action items/takeaways:
|
OK, let me summarize the cancellable promise approach.
Is your idea described well in [Plan B]? |
Oh. Conflict :). So, plan A and B are elaboration of the last bullet point of #297 (comment). Tell me if there's anything to correct. |
I think I was originally thinking of [Plan B] but while writing the end of my last comment I realized it was kind of dumb. So if promise cancellation is accomplished via But if we do promise cancellation via a cancellation token ("canceller") approach then I think we could allow [Plan D] (Plan A <-> Plan C, Plan B <-> Plan D, is the mapping.) |
[Plan D] is useful. [Plan C] also looks clean given current Fetch procedure (receive Response, then receive body via Streams) and one slight benefit I see is that we can forget
Do you mean |
Yes, sorry, I did mean I think we can delay deciding between [Plan A], [Plan C], and [Plan D] until we figure out cancellable promises in a bit more detail. But the important thing is that we do have a path forward that gives us all the abilities we want, and its impact on streams is essentially that we won't be able to cancel a pipe until we also figure out how to cancel a promise. |
Decision about forcible cancel regarding pipeTo() or any other operations requiring lock: See #297 (comment) |
Remaining issues in this thread are:
|
Per discussion in #297. We can always add it back later if we really want it, but it has become increasingly useless in the newer, reader-centric design.
Per discussion in #297. We can always add it back later if we really want it, but it has become increasingly useless in the newer, reader-centric design.
OK. Managed to convince @yutakahirano offline that auto-release is good. Am willing to remove closed, at least for now; we could potentially add it back later if someone comes up with a really good use case. #296 updated and build is passing. Ready for more review! Closing this issue. |
See discussion in #297. This commit implements the following changes: - Allow acquiring readers for closed or errored streams; they simply act closed or errored. - Stop auto-releasing readers when streams close/error. - Disallow canceling a stream that is locked to a reader (you should use the reader cancel). - Piping from a closed or errored stream will close or abort the destination stream, instead of immediately failing the pipe.
See discussion in #297. pipeTo now returns a { finished, unpipe() } object, instead of just a promise.
Per discussion in #297. We can always add it back later if we really want it, but it has become increasingly useless in the newer, reader-centric design.
See discussion in #297. This commit implements the following changes: - Allow acquiring readers for closed or errored streams; they simply act closed or errored. - Stop auto-releasing readers when streams close/error. - Disallow canceling a stream that is locked to a reader (you should use the reader cancel). - Piping from a closed or errored stream will close or abort the destination stream, instead of immediately failing the pipe.
See discussion in #297. pipeTo now returns a { finished, unpipe() } object, instead of just a promise.
Per discussion in #297. We can always add it back later if we really want it, but it has become increasingly useless in the newer, reader-centric design.
I read @domenic's pull request and would like to talk about getting / releasing reader. If you think the PR is the right place to discuss, feel free to close this issue.
getReader()
should succeed on closed streamImagine we have a Response (in Fetch API)
res
.res.body.getReader()
should succeed even when the response has an empty body. That meansres.body.getReader()
should succeed when the body is closed. The result is a closed reader.getReader()
should succeed on errored streamMainly for being consistent with the closed case. We do not lose anything by allowing this. The result is an errored reader.
Do we need auto-release?
Currently a reader is automatically released when it is closed or errored. Do we need the functionality?
It was introduced at #251 (comment), but given that our API is simpler than before and the current API requires a user to be sane, I would like to revisit the problem.
Concern: What happens when canceled via stream? What happens when canceled via reader?
Do we need
.closed
in stream?I don't think of a use case. If we drop it, Resource management of Response.body will be much simpler.
The usefulness may depend on whether if keep auto-release or not.
The text was updated successfully, but these errors were encountered: