-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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
stream: do not swallow errors with async iterators and pipeline #32051
stream: do not swallow errors with async iterators and pipeline #32051
Conversation
Something else is going on here. I don't understand how this can cause premature close. It seems that the The test can be further simplified to: {
const rs = new Readable({
read() {
setImmediate(() => {
rs.push('hello');
});
}
});
pipeline(rs, async function*(stream) {
/* eslint no-unused-vars: off */
for await (const chunk of stream) {
throw new Error('kaboom');
}
}, common.mustCall((err) => {
assert.strictEqual(err.message, 'kaboom');
}));
} EDIT: The throw inside the iterable seems to call iterator.return instead of iterator.throw which I find strange, but maybe that's the way it's supposed to work? for await (const chunk of stream) {
throw new Error('kaboom');
} this will call |
I thought the same as well, and I do not understand why the catch call is never reached. I was not be able to reproduce the problem with just our async iterator code. The “bug” comes from the interaction between all the streams and the async iterator. Not that for an async iterator in pipeline we have 3 finished() calls that gets into play (1 in the main async iterator, 1 inside the finish function called from return, and one inside pipeline). The internal error is swallowed because the iterator ends abruptly and it causes the other streams to close. Those premature closes are forwarded earlier than the error from the internal async iterator. At least, that’s my read of the problem. Let me know if you can crack this :/. |
That’s what I discovered as well. I think it’s how it works. |
Sorry, the close was a misclick. I don't like this solution but I can't really think of anything better...
If this is not an urgent issue please give me a few days to try to crack it before landing this. |
I can confirm this is the correct behaviour (I have absolutely no idea why though, I'd have to dig into old tc39 notes) |
@devsnek Do you have any advice here? We had a short mail conversation in regards to a related topic some time ago. In particular, I'm curious why the iterator protocol would not call EDIT: wow, nice timing @devsnek |
Ok this is basically a difference in the node stream model and the async iterator model. In node.js, the streams own errors that happen while they are being consumed ( |
To expand a bit: My mental model of |
6ac2f87
to
89b2368
Compare
@ronag this should be a better fix. The problem we were facing was a race between the ERR_STREAM_PREMATURE_CLOSE of the last stream and the error produced by the async iteration. I've solved the bug by having the callback called when all streams have been successfully destroyed and just not the last. |
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.
Nice! A few questions though.
Why not just set finishCount to the number of calls to wrap
? That way you only need to decrement it in the destroyer callback.
77019be
to
4d34ee6
Compare
Before this patch, pipeline() could swallow errors by pre-emptively producing a ERR_STREAM_PREMATURE_CLOSE that was not really helpful to the user. Co-Authored-By: Robert Nagy <[email protected]>
4d34ee6
to
e4c3f55
Compare
it changed too much since last review, PTAL.
@ronag @jasnell @addaleax @benjamingr PTAL. |
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.
Would prefer to keep final
in destroyer
Before this patch, pipeline() could swallow errors by pre-emptively producing a ERR_STREAM_PREMATURE_CLOSE that was not really helpful to the user. Co-Authored-By: Robert Nagy <[email protected]> PR-URL: #32051 Reviewed-By: Robert Nagy <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
Landed as d7fe554 |
Before this patch, pipeline() could swallow errors by pre-emptively producing a ERR_STREAM_PREMATURE_CLOSE that was not really helpful to the user. Co-Authored-By: Robert Nagy <[email protected]> PR-URL: #32051 Reviewed-By: Robert Nagy <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
Before this patch, pipeline() could swallow errors by pre-emptively
producing a ERR_STREAM_PREMATURE_CLOSE that was not really helpful
to the user.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes