-
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
Different behavior between transform function and async generator using pipelines #32363
Comments
@nodejs/streams |
Minimal repro on master. 'use strict';
const common = require('../common');
const assert = require('assert');
const { pipeline, PassThrough } = require('stream');
const cp = require('child_process');
if (process.argv[2] === 'child') {
pipeline(
process.stdin,
new PassThrough(),
process.stdout,
common.mustCall((err) => {
console.error('end');
})
);
return;
}
cp.exec([
'echo',
'"hello"',
'|',
`"${process.execPath}"`,
`"${__filename}"`,
'child'
].join(' '), common.mustCall((err, stdout, stderr) => {
console.log(err)
assert.ifError(err);
console.log(stdout);
})); |
Seems like |
So this fails: pipeline(
process.stdin,
new PassThrough(),
process.stdout,
common.mustCall((err) => {
console.error('end');
})
); while this doesn't: pipeline(
process.stdin,
p.on('end', () => {
process.stdout.end()
}),
process.stdout,
common.mustCall((err) => {
console.error('end');
})
); |
@addaleax This does not seem related to 'use strict';
const common = require('../common');
const assert = require('assert');
if (process.argv[2] === 'child') {
process.stdin
.pipe(process.stdout)
.on('finish', common.mustCall(() => {
console.log('finish');
}));
} else {
const cp = require('child_process');
cp.exec([
'echo',
'"hello"',
'|',
`"${process.execPath}"`,
`"${__filename}"`,
'child'
].join(' '), common.mustCall((err, stdout, stderr) => {
assert.ifError(err);
}));
} |
The reason this probably works with pipeline + generator is because that path does not use Maybe |
I believe this is the culprit https://github.com/nodejs/node/blob/master/lib/_stream_readable.js#L654. Unfortunately I don't understand this part at the moment. Basically |
|
@vweevers: Does that mean
Do we need a special case here in |
Not sure we can do that? Before completing, we'd want to make sure the writes to Alternative point of view: |
It is a bit random though... since this only applies for the
It can be closed, it's just that |
I can see that, but I can't see the documentation mentioning this particular thing? Should we add it? |
stdio (stderr & stdout) should for compatibility reasons not be closed/end():ed. However, this causes pipeline with a stdio destination to never finish. This commit fixes this issue at a performance cost. Refs: nodejs#7606 Fixes: nodejs#32363
Ah, my understanding of it was outdated. Since node v10.12.0 (see #23053 and ERR_STDOUT_CLOSE) you can indeed close these streams. Before they used to throw an error, now they allow it but "secretly" don't close the underlying fd. I would guess that the |
Confirmed, the 9-year-old commit that introduced the now-defunct throwing behavior also introduced the pipe workaround: 13324bf |
@vweevers: So is a possible fix to make src.pipe(dst);
if (dst === process.stdout) {
src.on('end', () => dst.end());
} |
I think so, but because there's so much history here, let's give the mentioned folks some time to respond. |
So what should we do about this? |
I can PR a delete of the 2nd and 3rd lines if that's all it takes to solve. |
@Xstoudi seems there is a little more to it unfortunately, #32373 (comment) |
@ronag Do we not want to fix this for |
Was closed through the commit. I think that's a different issue than this though. But yes, I think we should fix it in |
Can we safely do that? Because we would be calling |
I think calling end twice is safe in this case. |
stdio (stderr & stdout) should for compatibility reasons not be closed/end():ed. However, this causes pipeline with a stdio destination to never finish. This commit fixes this issue at a performance cost. Refs: #7606 Fixes: #32363 PR-URL: #32373 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
stdio (stderr & stdout) should for compatibility reasons not be closed/end():ed. However, this causes pipeline with a stdio destination to never finish. This commit fixes this issue at a performance cost. Refs: #7606 Fixes: #32363 PR-URL: #32373 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
What steps will reproduce the bug?
index.mjs:
then
echo "hello" | node index.mjs
ends up like this:but if you replace asyncGen in the pipeline by
new PassThrough()
, it ends up like this:As you can see, the callback is never called.
How often does it reproduce? Is there a required condition?
What is the expected behavior?
What do you see instead?
Additional information
I don't really know if it's an expected behavior or a bug to be honest. As I can't find anything related in the documentation, it feels like a bug.
The text was updated successfully, but these errors were encountered: