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

stream: restore flow if there are 'data' handlers after once('readable') #22209

Closed
wants to merge 1 commit into from

Conversation

mcollina
Copy link
Member

@mcollina mcollina commented Aug 9, 2018

In #18994, we made 'readable'  take precedence over 'data'/resume() and pause(). However, we didn't take into account situation where both 'readable'  and 'data' event handler were present at the same time. This PR addresses it by starting flowing after 'readable' is removed.

Fixes: #21398

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added the stream Issues and PRs related to the stream subsystem. label Aug 9, 2018
@mcollina
Copy link
Member Author

mcollina commented Aug 9, 2018

This is an alternative implementation of #21696.
cc @lundibundi

@mcollina
Copy link
Member Author

mcollina commented Aug 9, 2018

@lundibundi
Copy link
Member

It seems like this one has the same flaws my PR had at the beginning

  • ignoring user pause
  • piping with .on('readable') fails

But the first one is documented now.
So basically there is no way to pause stream if you use 'readable' and pipe doesn't work. The latter is as before but I don't think it's a good behavior, though if we go with this PR I think it has to be documented explicitly in .pipe doc, as well as that stream will be set to paused if you add 'data' listener after 'readable'.

@mcollina
Copy link
Member Author

mcollina commented Aug 9, 2018

ignoring user pause

That works exactly as expected. If resume() is ignored, why pause()  shouldn't?
stream.pause() and stream.resume() are methods to be used with .on('data').

piping with on('readable') fails

Which is as expected. on('readable') is a method of consuming data from a stream with backpressure, so a user has to consume it via stream.read() calls. Side note, without #18994 stream.read() always returned null when used with stream.pipe().

@lundibundi
Copy link
Member

Yeah, this may be better as it simplifies the implementation a bit and signifies the fact that you shouldn't use 'readable' with 'data'. But as I said we have to better document it as issues of incorrect usage of streams are constantly popping up.

@mcollina
Copy link
Member Author

mcollina commented Aug 9, 2018

I'll add some more docs for review tomorrow.

CI: https://ci.nodejs.org/job/node-test-pull-request/16301/

@@ -618,6 +618,12 @@ instance, when the `readable.resume()` method is called without a listener
attached to the `'data'` event, or when a `'data'` event handler is removed
from the stream.

Adding a [`'readable'`][] event handler automatically make the stream to
stop flowing, and the data to be consumed via
[`readable.read()`][]. If the [`'readable'`] event handler is removed,
Copy link
Contributor

@vsemozhetbyt vsemozhetbyt Aug 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[`readable.read()`][]-> [`readable.read()`][stream-read]?

Adding a [`'readable'`][] event handler automatically make the stream to
stop flowing, and the data to be consumed via
[`readable.read()`][]. If the [`'readable'`] event handler is removed,
then the stream will start flowing again if there is a [`data`][] event
Copy link
Contributor

@vsemozhetbyt vsemozhetbyt Aug 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[`data`][] -> [`'data'`][]?

@mcollina
Copy link
Member Author

CITGM seems ok.

@mcollina
Copy link
Member Author

@mcollina
Copy link
Member Author

@vsemozhetbyt PTAL

@vsemozhetbyt
Copy link
Contributor

Doc part LGTM.

@mcollina
Copy link
Member Author

@mafintosh @addaleax PTAL.

@mcollina
Copy link
Member Author

@oyyd
Copy link
Contributor

oyyd commented Aug 21, 2018

@mcollina I think this relates to #21122. What if we don't call read() inside the callback of 'readable' ? This might be regarded as an undefined behavior but calling on('data') before on('readable') like below:

const fs = require('fs')
const { resolve } = require('path')

const source = resolve(__dirname, 'index.js')
const target = resolve(__dirname, 'copy.js')

const reader = fs.createReadStream(source)
const writer = fs.createWriteStream(target);

reader.on('close', () => {
    console.log('reader closed');
});

writer.on('close', () => {
    console.log('writer closed');
});

reader.on('data', () => {
  console.log('receive data')
})

reader.on('readable', () => {
  // DO NOT `reader.read()`
})

Will print:

receive data
reader closed

However, change the order of binding these two events will result in different behaviors:

const fs = require('fs')
const { resolve } = require('path')

const source = resolve(__dirname, 'index.js')
const target = resolve(__dirname, 'copy.js')

const reader = fs.createReadStream(source)
const writer = fs.createWriteStream(target);

reader.on('close', () => {
    console.log('reader closed');
});

writer.on('close', () => {
    console.log('writer closed');
});

reader.on('readable', () => {
  // DO NOT `reader.read()`
})

reader.on('data', () => {
  console.log('receive data')
})

Will print nothing and exit.

Also, replace reader.on('data') with reader.pipe(writer) will cause similar results.

@mcollina
Copy link
Member Author

@oyyd yes it does. Unfortunately the documentation for #18994 was not clear enough. This resolves an edge case for that PR and it improves the docs.

I've also replied in the issue you linked.

@oyyd
Copy link
Contributor

oyyd commented Aug 21, 2018

I see, thanks.

@mcollina
Copy link
Member Author

@mafintosh
Copy link
Member

LGTM, nice fix

@mcollina
Copy link
Member Author

@mcollina
Copy link
Member Author

@nodejs/build I can't get centos7-64-gcc6 to pass, see https://ci.nodejs.org/job/node-test-commit-linux/20945/nodes=centos7-64-gcc6/console.

This looks like an infra issue, see nodejs/build#1468.

@jasnell jasnell added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Aug 21, 2018
@Trott
Copy link
Member

Trott commented Aug 22, 2018

Trott pushed a commit to Trott/io.js that referenced this pull request Aug 22, 2018
@Trott
Copy link
Member

Trott commented Aug 22, 2018

Resume Build resulted in a green CI run.

Landed in 98cf84f.

@Trott Trott closed this Aug 22, 2018
targos pushed a commit that referenced this pull request Aug 24, 2018
targos pushed a commit that referenced this pull request Sep 3, 2018
daprahamian added a commit to mongodb/node-mongodb-native that referenced this pull request Sep 17, 2018
Fixes test failure causes by combination of nodejs/node#22209 and
an ambiguous test.
daprahamian added a commit to mongodb/node-mongodb-native that referenced this pull request Sep 17, 2018
Fixes test failure causes by combination of nodejs/node#22209 and
an ambiguous test.
mbroadst pushed a commit to mongodb/node-mongodb-native that referenced this pull request Sep 18, 2018
Fixes test failure causes by combination of nodejs/node#22209 and
an ambiguous test.
daprahamian added a commit to mongodb/node-mongodb-native that referenced this pull request Sep 18, 2018
Fixes test failure causes by combination of nodejs/node#22209 and
an ambiguous test.
kiku-jw pushed a commit to kiku-jw/node-mongodb-native that referenced this pull request Feb 11, 2019
Fixes test failure causes by combination of nodejs/node#22209 and
an ambiguous test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants