Skip to content
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

pipeline leaves a hanging error handler #35452

Closed
szmarczak opened this issue Oct 1, 2020 · 25 comments · Fixed by #41954
Closed

pipeline leaves a hanging error handler #35452

szmarczak opened this issue Oct 1, 2020 · 25 comments · Fixed by #41954
Labels
good first issue Issues that are suitable for first-time contributors. stream Issues and PRs related to the stream subsystem.

Comments

@szmarczak
Copy link
Member

szmarczak commented Oct 1, 2020

  • Version: 14.12.0
  • Platform: Linux SZM-DESKTOP 4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
  • Subsystem: stream

What steps will reproduce the bug?

const {pipeline, Duplex, PassThrough} = require('stream');

const a = new PassThrough();
a.end('foobar');

const b = new Duplex({
    write(chunk, encoding, callback) {
        callback();
    }
});

pipeline(a, b, error => {
    if (error) {
        throw error;
    }
    
    console.log(b.listenerCount('error'));
    setTimeout(() => {
        console.log(b.listenerCount('error'));
        b.destroy(new Error('no way'));
    }, 100);
});

How often does it reproduce? Is there a required condition?

Always.

What is the expected behavior?

0
0
[Uncaught] Error: no way

What do you see instead?

2
1

/cc @ronag

@ronag
Copy link
Member

ronag commented Oct 1, 2020

This is by design.

@ronag
Copy link
Member

ronag commented Oct 1, 2020

The docs say:

stream.pipeline() leaves dangling event listeners on the streams after the callback has been invoked. In the case of reuse of streams after failure, this can cause event listener leaks and swallowed errors.

@szmarczak
Copy link
Member Author

This is by design.

Can this design be improved? Or is this a no?

@possum1102
Copy link

Hmmm

@nodejs nodejs deleted a comment Oct 3, 2020
@nodejs nodejs deleted a comment Oct 3, 2020
@lpinca lpinca added the stream Issues and PRs related to the stream subsystem. label Oct 6, 2020
@targos
Copy link
Member

targos commented Dec 13, 2020

/cc @nodejs/streams

@ronag
Copy link
Member

ronag commented Dec 13, 2020

I don’t think there is anything more to do here. Unless someone has suggestion?

@vweevers
Copy link
Contributor

@ronag I agree. Using pipeline() means letting pipeline() manage the lifetime of the streams, after which the streams are destroyed and should not be touched anymore.

@szmarczak
Copy link
Member Author

Using pipeline() means letting pipeline() manage the lifetime of the streams

It does not. b.destroyed is false. So the readable side is still open. The fix is either to remove the hanging handler or destroy the end stream.

@vweevers
Copy link
Contributor

I missed that the last stream in the example is a duplex stream. Not sure how that should behave, because the readable side can't be consumed.

@szmarczak
Copy link
Member Author

the readable side can't be consumed.

What do you mean?

@vweevers
Copy link
Contributor

If it were pipeline(readableStream, duplexStream, writableStream) then the readable side of duplexStream would be piped into writableStream. But if duplexStream is the last stream in the pipeline, then no one is reading from it.

If we swap the duplex stream in your example for a writable stream, then it does get destroyed:

const {pipeline, PassThrough, Writable} = require('stream')

const a = new PassThrough()
a.end('foobar')

const b = new Writable({
  write (chunk, encoding, callback) {
    callback()
  }
})

pipeline(a, b, function (err) {
  if (err) {
    throw err
  }

  console.log(a.destroyed) // true
  console.log(b.destroyed) // true
})

@szmarczak
Copy link
Member Author

But if duplexStream is the last stream in the pipeline, then no one is reading from it.

You don't know. It's readable so it's not destroyed. Something can be reading it a tick later.

@ronag
Copy link
Member

ronag commented Dec 14, 2020

Removing the error handler on the last (returned) stream might make sense if it is readable. @nodejs/streams wdyt?

@mcollina
Copy link
Member

I'm ok in removing it when we do not call stream.destroy().

@ronag
Copy link
Member

ronag commented Dec 14, 2020

@szmarczak would you like to prepare a PR?

@szmarczak
Copy link
Member Author

Sure, would love to.

@mcollina
Copy link
Member

@szmarczak any updates here?

@mcollina mcollina added the good first issue Issues that are suitable for first-time contributors. label Apr 22, 2021
@szmarczak
Copy link
Member Author

Sorry, totally forgot about this one. Will sketch something in a few hours.

@joaoofreitas
Copy link

Sorry, totally forgot about this one. Will sketch something in a few hours.

Count on me to help! @szmarczak

@szmarczak
Copy link
Member Author

@joaoofreitas awesome! Feel free to send a PR first and I'll chime in and let you know my thoughts :D

@lvndry
Copy link

lvndry commented Jul 8, 2021

If this is still work in progress I'd be happy to help

@mcollina
Copy link
Member

mcollina commented Jul 8, 2021

Sure thing!

@Heikrana
Copy link

Heikrana commented Feb 1, 2022

Hey @mcollina. Can I help in this? (If @lvndry isn't working on it anymore)

I'm new to NodeJS and to Open Source. Might be hard for me, but I'd like to try.

@mcollina
Copy link
Member

mcollina commented Feb 2, 2022

@Heikrana this might end up a bit too hard. Maybe try something easier first? It's one of the hardest part of Node.

@Heikrana
Copy link

Heikrana commented Feb 2, 2022

@Heikrana this might end up a bit too hard. Maybe try something easier first? It's one of the hardest part of Node.

Okay, I see your point. I've been trying to understand the stream API and yeah, it's a bit confusing.
I'd still try to solve this issue (since no one else is working on it).

But in the meantime, can you suggest me some resources (which would help me contribute to NodeJS) or another issue which might be more of my level. I really want to be part of this community :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Issues that are suitable for first-time contributors. stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants