-
Notifications
You must be signed in to change notification settings - Fork 30k
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
[x] stream: error multiple iterators #29064
Conversation
ce96ebc
to
ac81e03
Compare
5f44ded
to
8e36d58
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work! I've left a few things to change.
I would like to know what @benjamingr and @devsnek think about this one, as it's a tricky case.
for await (const b of r) { | ||
} | ||
} catch (err) { | ||
assert.strictEqual(err.code, 'ERR_STREAM_ITERATOR_EXISTS'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test would have to be split in two. The previous code verified that iterating on an ended stream completes
- this would have to be tested without the first for await
. Then , we should add a new test about the ERR_STREAM_ITERATOR_EXISTS
error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not convinced we should do this - there are cases where creating multiple iterators might be valid and there are cases where I'd want to create an iterator - consume part of the stream, throw it away - then create another iterator to consume the rest of the stream.
const cursor = database.query(...).cursor();
for await(const item of cursor) {
if (item === 'special-item') {
// found first special item
report(item);
}
}
for await(const item of cursor) {
// do something with all future items
} In this case the user might think they have a single iterable but they actually have two. |
This is not currently possible. Adding |
Oh yeah, I remember that :D That is correct behavior at a second glance, a |
Unfortunately this is complex topic. Think about it a bit more, and let us know! |
@mcollina do we actually have a choice though? We don't have any concept of multiple readables for a resource in core (do we?) - and if someone wants to build a package that Is there actually an alternative other than throwing? (or erroring later) |
I'll sort out the PR comments once we have more of a consensus. |
I think returning the same iterator might be considered an option. |
I guess that makes sense since it aligns with having the behaviours people expect for the same Readable for the same data source. |
You could have a break... oh no... that will destroy the stream. So in this case we would need to reference count the number of createIterator vs destroy iterator requests, before we destroy the stream? |
Doing refcounting would just be confusing IMO, I am fine with either this behavior (throw) or Matteo's suggestion (same iterator). |
It's just as confusing without refcounting :D. I totally got the nested behaviour wrong. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally I like this (we do the same thing in web streams), but we should have a way to release the lock somehow.
Also for the above point about wanting multiple consumers, the general approach from other languages and from web streams is to tee the origin stream with a buffered intermediary (https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/tee) |
Throw if creating multiple async iterators from the same stream.
Refs: #28997
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes