-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
finished(stream, cb)
invokes callback too early
#32032
Comments
finished(stream, cb)
invokes callback too early
I think the current behavior is fine. What would be the actual difference in waiting for close instead? (minus backward compatibility, which would postpone any changes for a long time :/). |
I guess 2 things, an error from resource cleanup might be swallowed also making assumption in regards to whether consider: // Creates internally a file called "foo.tmp"
const s = new MyStream();
s._destroy((err ,cb) => {
fs.unlink("foo.tmp", cb);
});
finished(s, (err) => {
// Code that assumes that _destroy has completed, e.g. "foo.tmp" has been removed.
}); I'll give that I'm grabbing a bit at straws but I still think it's worth at least explicitly mentioning in the docs. |
I've been bitten by this too, but as y'all mentioned, there's only one proper way to solve it, namely having all streams emit close. +1 for documenting it until then. |
There is also the option to assume e.g.
However, that would assume that "modern" streams are properly implemented in terms of |
I think ultimately, |
It is default in master. Not being able to opt-out is going to be difficult. We have some code in core that depends on it which I find unlikely to be refactored to such a degree (though other parts are work in progress). |
We could also go even more conservative:
|
If it (finishing on close) only works for some streams, it might not be worth it, because you can't rely on it without checking the implementation details of every stream. |
What if streams had a way to say "yes, I always emit close"? Like |
streams should always emit |
Exactly, haha. There are too many streams out there that by today's standards are broken. The only sensible value for (I would strongly prefer a solution that's baked into streams and doesn't require action from module authors, but it seems that's not an option due to aforementioned node internals, so here we are). |
I've also noticed that https://github.com/nodejs/node/blob/master/lib/internal/streams/pipeline.js#L44 depends on this behavior where |
Yeah, function loop() {
stream.pipeline(getStreamWithLock(), ..., function () {
loop()
})
} |
I'm definitely +1 if we can soft-detect this on a stream-by-stream basis |
What are the preferred semantics here? I think pipeline should preferrably only call the callback once every stream has emitted @mcollina: Even if we exclude "legacy" streams (we can detect pre v14), we would potentially break "modern" streams that explicitly set |
Broken according to modern stream semantics, but still usable. It would have been different if If we favor backwards compatibility and can't reliably detect whether a particular stream will emit close, or invent a way for the stream to signal that it will emit close, we must assume it doesn't. On the other hand, I want streams to move forward (until we can say "it just works™") so I'm torn. |
I don't think CITGM would give us enough coverage, because every module must have its own tests for the close event. |
This reminds me of |
From my point of view, I think we should check if |
Pipeline uses eos which will invoke the callback on 'finish' and 'end' before all streams have been fully destroyed. Fixes: nodejs#32032
The semantics of
finished
is to invoke the callback on'end'
and'finish'
. The problem with this is that this does not mean that the stream is actually "finished", i.e. it might still emit'error'
and has probably not yet freed all resources since'close'
is not yet emitted.The reason we invoke it early in this way is because not all stream actually emit
'close'
. I'm a little unsure how to resolve this and whether this is worth resolving.One way could be to use
setImmediate
orsetTimeout
before invoking the callback in'end'
/'finish'
in order to give a chance for'error'
or'close'
to be emitted. However, that is very much imperfect.We might want to at least clarify this in the docs.
Thoughts? @nodejs/streams
The text was updated successfully, but these errors were encountered: