-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
The error
handler isn't removed on successful stream async iteration
#32995
Comments
I realize that function eof callback didn't call up diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js
index 4742391fd7..f6cac90dc0 100644
--- a/lib/internal/streams/end-of-stream.js
+++ b/lib/internal/streams/end-of-stream.js
@@ -8,6 +8,7 @@ const {
ERR_STREAM_PREMATURE_CLOSE
} = require('internal/errors').codes;
const { once } = require('internal/util');
+const debug = require('internal/util/debuglog').debuglog('stream');
function isRequest(stream) {
return stream.setHeader && typeof stream.abort === 'function';
@@ -60,6 +61,7 @@ function eos(stream, opts, callback) {
(opts.readable !== false && isReadable(stream));
const writable = opts.writable ||
(opts.writable !== false && isWritable(stream));
+ debug('eos', readable, writable);
const wState = stream._writableState;
const rState = stream._readableState;
@@ -152,6 +154,7 @@ function eos(stream, opts, callback) {
}
return function() {
+ debug('eos cleanup');
callback = nop;
stream.removeListener('aborted', onclose);
stream.removeListener('complete', onfinish); \node\Release\node.exe C:\Users\Himself65\Desktop\github\test\1.js
STREAM 21764: eos true false
STREAM 21764: on readable 0 false
STREAM 21764: read undefined
STREAM 21764: need readable true
STREAM 21764: length less than watermark true
STREAM 21764: do read
STREAM 21764: readableAddChunk chunk
STREAM 21764: emitReadable true false
STREAM 21764: emitReadable false
STREAM 21764: readableAddChunk null
STREAM 21764: onEofChunk
STREAM 21764: emitReadable false true
STREAM 21764: endReadable false
STREAM 21764: readable nexttick read 0
STREAM 21764: read 0
STREAM 21764: endReadable false
STREAM 21764: emitReadable_ false 0 true
STREAM 21764: flow false
STREAM 21764: endReadableNT false 0
STREAM 21764: endReadableNT true 0
1
Process finished with exit code 0 I didn't work on this part before so I don't know if it's a bug or a feature and this appears on the versions which more than cc @nodejs/streams |
I think this is by design. Anything that uses |
Yes, it's by design. Closing |
@himself65 It might be worth to add a corresponding section under async iterator:
|
yes, that's better. so I reopen this until PR fixes |
It should be possible to do so in all cases, including async iterators. |
What incorrect stream implementations? |
Can you link to a PR that introduced this change please? |
I don't see how it would be possible with async iterators. |
Those that emit |
E.g. expose it via |
Why not? |
As far as I can tell, it's been like that from the beginning in terms of async iterators. |
Then it should throw an
Ok, I'll check this. |
I don't see the value and it's logically weird. |
See:
|
It's just inconsistent behavior. |
That is something we want to avoid. The point of |
In what way? |
@mcollina Might have more information regarding the motivation for this behavior. |
That streams inherit from event emitter.
The users should be aware of this problem and fix their implementations so they are correct. Still, I see no reason why this incorrect implementations are allowed. |
But we are talking about async iterator now?
Because we don't want to break the ecosystem? |
👍
Hmm... That's the idea of breaking changes aka major changes. Anyway, if it needs to be the way it is, I'm fine with that. I understand your position. |
@himself65 This was documented in #28997 |
I agree with you. There is however is large range of opinions on this topic in regards to breaking vs value. |
LTS versions mean are more valuable IMO |
I also think this should be properly fixed. And the https://github.com/nodejs/node/pull/28997/files docs does not make it clear enough the consequences of the permanent error handler and what the user is supposed to do about it. |
I don't understand why this is a problem? The stream is destroyed and completed. |
It's surprising in that, when you use an async iterator, you never add an |
I guess, basically once you have converted a stream into an async iterator it should not really be used as a stream anymore. Unfortunately javascript does not have move semantics. It's unfortunate and I also would like to fix it but I don't see any clean way of resolving this. Also I don't really see how it is a big problem?
But we are talking about async iterator now? for await (const chunk of stream) {
} Does not leave much of an API surface. |
You can reuse that stream in terms of error handling. Got does this. In my @novemberborn's example is perfectly valid. |
How? Once the for await loop completes or exits it should not be emitting any further errors. Sorry, I do not follow the rest of your example.
Sorry, I do not follow. |
How would this be different from:
|
But async iterator utilizes streams, that's the thing. They mean almost 99% the same. You understand this already.
So there shouldn't be a hanging
Let me explain so you understand this correctly: the async iterator leaves a hanging
You cannot guarantee that someone didn't attach their own listener. |
Re-use the error event? Are you doing
Once the read of the async iterator is completed the stream is It sounds to me like you are trying to use streams in a way it was not really intended.
Yes, so how would |
You are overriding emit here. That's really a bit outside of supported usage. You are a bit on your own risk here. |
I'm not really following along here. If you prefer maybe a google hangout call or something would be more constructive? Would help if I understand your use case better. |
Exactly.
Otherwise it would be necessary to delay the
I know, sorry I haven't set up a more construcive example yet. Will do. |
Yea, that kind of breaks some stream assumptions.
Cool. I'm more than happy to try and help out but digging into the details of got is a little outside my timeframe.
Could you wait for close instead? |
@szmarczak Regarding http-timer. You probably want to listen to Also, have you looked at |
Nice find, thanks :) I guess I look at the docs not so often, this definitely solves the I'm sketching some code for the original problem rn.
I think it would be more useful to throw on every action if the stream is destroyed to avoid ambiguity.
Thanks for taking your time. I really appreciate it!
That would work too, definitely. |
I would recommend closing this. The dangling I'm closing. |
@ronag I made an example of 237 lines (sorry that's the shortest example I came up with): https://gist.github.com/szmarczak/e7eb659bebb33bceb7577e90d7216aa3 The line I care the most is line no. 198.
Call
Have you actually encountered a package that benefits from this? Or was this just "it's possible, so let's do this"? Nevermind, let's forget this question. It doesn't change anything. But I'm strongly against the latter. Sorry if my behavior was a bit harsh, I was 10000% convinced this was a bug and I didn't expect how it turned out to be. |
A significant amount of "old/legacy" stream packages could emit multiple |
What steps will reproduce the bug?
How often does it reproduce? Is there a required condition?
Always.
What is the expected behavior?
What do you see instead?
Additional information
The
error
handler seems to be from https://github.com/nodejs/node/blob/master/lib/internal/streams/end-of-stream.jsThe text was updated successfully, but these errors were encountered: