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.finished calls callback when writable stream still has pending callbacks #46170

Closed
watson opened this issue Jan 11, 2023 · 4 comments · Fixed by #53438
Closed

stream.finished calls callback when writable stream still has pending callbacks #46170

watson opened this issue Jan 11, 2023 · 4 comments · Fixed by #53438
Labels
stream Issues and PRs related to the stream subsystem.

Comments

@watson
Copy link
Member

watson commented Jan 11, 2023

Version

>=17.0.0 (verified all the way up to the latest 19.7.0)

Platform

Darwin watson-2.local 22.2.0 Darwin Kernel Version 22.2.0: Fri Nov 11 02:03:51 PST 2022; root:xnu-8792.61.2~4/RELEASE_ARM64_T6000 arm64

Subsystem

stream

What steps will reproduce the bug?

Run the following code and observe that the last assert throws because the stream still has a pending callback (because setImmediate hasn't called cb yet inside the streams write function:

const { strict: assert } = require('node:assert');
const { Duplex, finished } = require('node:stream');

const stream = new Duplex({
  write (chunk, enc, cb) {
    setImmediate(cb);
  }
});

stream.end('foo');

finished(stream, { readable: false }, (err) => {
  console.log('Finished!');
  assert.equal(err, undefined);
  assert.equal(stream._writableState.pendingcb, 0);
});

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

Always

What is the expected behavior?

I wouldn't expect stream.finished to call its callback if there's still pending callbacks on the writable side.

What do you see instead?

I would expect stream.finished to wait calling its callback until stream._writableState.pendingcb is 0.

Additional information

This is a follow up to issue #45281, which I had thought would fix the problem.

It's worth noting that this problem only occurs if it's a Duplex or Transform stream and only if finished is passed readable: false as an option.

Additionally, It might just be me who doesn't understand how stream.finished is supposed to behave in this instance, in which case I'm just using it wrong. But if so, I'm not sure how to know when there's no more pending callbacks?

@VoltrexKeyva VoltrexKeyva added the stream Issues and PRs related to the stream subsystem. label Jan 12, 2023
@ErickWendel
Copy link
Member

It really seems to be a bug! I'm troubleshooting it and will open a PR with the solution as soon as possible!

@ErickWendel
Copy link
Member

ErickWendel commented Mar 14, 2023

I was digging a bit and it seems that when you call the .end function before the finished is attached it cannot handle it.

If I put a setTimeout so the .end is executed right after the finished is attached it works as expected:

const { strict: assert } = require('node:assert')
const { Duplex, finished } = require('node:stream')

const stream = new Duplex({
  write(chunk, enc, cb) {
    setImmediate(cb)
  }
})
setTimeout(() => stream.end('foo'), 200);

finished(stream, { readable: false }, (err) => {
  console.log('Finished!')
  assert.strictEqual(err, undefined)
  assert.strictEqual(stream._writableState.pendingcb, 0)
})

Gonna ping the team here so we might discuss if this is actually the expected behavior

EDIT: When looking at this piece and checking the pendingcb it's set to 1 (which means it's not finished) gonna inspect more but it seems to me to be some unexpected behavior

cc @nodejs/streams

@ronag
Copy link
Member

ronag commented Mar 14, 2023

This looks suspicious. Same problem on v19?

@ErickWendel
Copy link
Member

This looks suspicious. Same problem on v19?

I've tested from source and v19.7.0. Both have the same output

jakecastelli added a commit to jakecastelli/node that referenced this issue Jun 13, 2024
jakecastelli added a commit to jakecastelli/node that referenced this issue Jun 13, 2024
targos pushed a commit that referenced this issue Jun 20, 2024
Fixes: #46170
PR-URL: #53438
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
sophoniie pushed a commit to sophoniie/node that referenced this issue Jun 20, 2024
Fixes: nodejs#46170
PR-URL: nodejs#53438
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
bmeck pushed a commit to bmeck/node that referenced this issue Jun 22, 2024
Fixes: nodejs#46170
PR-URL: nodejs#53438
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
marco-ippolito pushed a commit that referenced this issue Jul 19, 2024
Fixes: #46170
PR-URL: #53438
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
marco-ippolito pushed a commit that referenced this issue Jul 19, 2024
Fixes: #46170
PR-URL: #53438
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants