-
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
stream: ensure Stream.pipeline re-emits errors without callback #20437
Conversation
lib/internal/streams/pipeline.js
Outdated
// TODO: Should eos cleanup after itself? | ||
// Ref https://github.com/mafintosh/end-of-stream/pull/12 | ||
cleanup(); | ||
|
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 seems to make sense, but I find it hard to tell how this part of the change relates to the rest. It feels like this should be something that comes with tests too?
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.
@addaleax so i stumbled around for ~2 days on this. Without cleaning up after end-of-stream, my re-emitted error was still being handled by the error
handler that end-of-stream attached and I couldn't get an uncaughtException
to be emitted. Once I added the cleanup, it emitted with no issues.
Would that go in this PR? A separate commit? I'm not sure the process here.
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.
Okay, makes sense. I think single PR and single commit is fine (but especially in the case of splitting into commits that correspond to logical changes you can use your own judgement). I think you can feel free to add a comment here that describes how this relates to the error handling, but this should be fine as-is.
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've forced pushed an updated comment that describes what I've explained above.
a490a89
to
d42c4d4
Compare
Personally I'm 👎 on this. Emitting errors on other streams can have unintended side effects, which is why pipeline/pump tries not to do that in the first place. If all streams were "modern" you could call destroy(err) on them but thats not gonna behave well in streams < node 10 unless they have a custom destroy handler. Changing behavior based whether a cb is passed or not can lead to tricky bugs imo. If people fell strongly about this I'd make the noop cb throw the error instead. |
@mafintosh I with @phated in that I think we should definitely do something that does not just swallow the errors silently… |
I agree with @mafintosh that this is likely not the best approach. Perhaps if |
@addaleax I wouldn't say errors are swallowed silently. On error the entire pipeline is shut down and destroy handlers are called on all streams. If you wanna be notified about this outside of your stream, you can pass a cb. Lots of use-cases of pump I've seen in the wild don't pass a cb, so if pipeline were to help them they'd have to pass in noop's. I don't feel strongly though about that part (I do about the re-emitting errors part tho), as pump still exists and gonna keep that old behaivor. |
I'm fine if we avoid re-emitting the error and switch it to throwing in the noop - all I really care about is that the error is actually surfaced when there's no way to watch for it (not passing a callback). Should I update the PR? |
@jasnell if I understand your approach correct you want to do: pipeline()
function pipeline(callback) {
callback = callback || (err) => {
if (err)
throw err;
}
// Do stuff
} To me this does not seem like a good approach since this will always end up as uncaught exception. Or did I misunderstand something? I personally suggest to just force the user to always add a callback. If non is added, we just throw an error as we do in other APIs as well. If the user wants to ignore errors, that is totally fine. |
@phated I would do that, yes. 👍 It seems like that’s at least something that you, me, @jasnell and @mafintosh can be behind.
@BridgeAR Also okay with me, but maybe for a follow-up PR since that’s tightening up behaviour even more? |
d42c4d4
to
c636365
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.
Still LGTM
It does tighten the current rule but I highly prefer that over the current PR implementation. I think throwing async is a really bad idea. Using emit would be a way the user could deal with it properly but always triggering uncaught exceptions is 😕 |
I agree that generating uncaught exceptions is 😕, but it’s something for which users have a clear way to address. More practically speaking, I think this PR could pass as not being semver-major (because there are cases where it’s known that no error is going to occur, and for the other cases this is effectively not silencing errors that should not be silenced, so a bug fix) whereas making the callback non-optional is definitely semver-major imo. |
Where are we at on this one? Definitely needs a rebase. |
This has been sitting for approval and feedback for a long time and I probably won't have time to rebase this coming up. Can someone else take that on? |
@mafintosh are you still -1 on this? |
@mcollina I think there are plenty of valid usecases where you don't want a cb because all error handling is contained in the pipeline (like a simple I wouldn't block a merge though if people felt like it's super important. This change https://github.com/nodejs/node/pull/20437/files#diff-eefad5e8051f1634964a3847b691ff84R49 should not be there IMO though as it makes error handling in practice tricky. With that change if a stream emits an error after |
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.
Marking my request of change explicit, so it does not get landed accidentally.
lib/internal/streams/pipeline.js
Outdated
// | ||
// TODO: Should eos cleanup after itself? | ||
// Ref https://github.com/mafintosh/end-of-stream/pull/12 | ||
cleanup(); |
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 think this should not be done here. 'error'
can still happen after 'end'
, making error handling more tricky.
@mafintosh as a general thing: you would be strongly against requiring a callback all the time? This is the default for pretty much everything async in Node.js and it would also solve this issue. Every user could easily just add a no-op callback in case they want to ignore that. Adding an explicit documentation about this should probably sufficient to explain this to users, don't you think so? |
@BridgeAR not strongly against it, just personal preference. |
Fixes an issue where Stream.pipeline wouldn't re-throw errors on a stream if no callback was specified, thus swallowing said errors. Fixes: nodejs#20303
c636365
to
44d3fe3
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.
LGTM
This is ready to land with a green CI. |
👍 |
Landed in c1012b4, thanks for the PR! |
Fixes an issue where Stream.pipeline wouldn't re-throw errors on a stream if no callback was specified, thus swallowing said errors. Fixes: #20303 PR-URL: #20437 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
Fixes an issue where Stream.pipeline wouldn't re-throw errors on a stream if no callback was specified, thus swallowing said errors. Fixes: #20303 PR-URL: #20437 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
Fixes an issue where Stream.pipeline wouldn't re-emit errors
on a stream if no callback was specified, thus swallowing
said errors.
Fixes: #20303
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes