Skip to content

refactor: use stream.finished() instead of custom implementation #56

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Phillip9587
Copy link

@Phillip9587 Phillip9587 commented Apr 29, 2025

Context

There have been previous efforts to modernize usage of on-finished, particularly around replacing it with stream.finished(), while still depending on isFinished() method from on-finished.
This PR tries to consolidate and properly implement those ideas within on-finished itself.

Related PRs:

Changes

This pull request refactors the on-finished package to use the native stream.finished() while maintaining compatibility with previous behaviour.

  • Replaced the ee-first library with the stream.finished utility from Node.js for handling message and socket events, improving compatibility with modern Node.js versions. (index.js, index.jsL92-R137)
  • Removed legacy patches for Node.js 0.8, including patchAssignSocket and tryRequireAsyncHooks functions, as they are no longer relevant. (index.js, index.jsL179-R182)

BREAKING CHANGES

stream.finished() is available since Node.js 10.0.0.


cc: @bjohansebas @UlisesGascon

Comment on lines 37 to 40
if (isFinished(msg) !== false) {
defer(listener, null, msg)
setImmediate(listener, null, msg)
return msg
}
Copy link
Author

Choose a reason for hiding this comment

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

The if block can be removed if we only accept Streams. There is a test with an unknown object blocking this change:

 it('should invoke listener given an unknown object', function (done) {
    onFinished({}, done)
  })

@bjohansebas
Copy link
Member

bjohansebas commented Apr 29, 2025

I'm in favor of this if it ensures that body-parser keeps working with AsyncLocalStorage

More than the tests passing here, I mean that they should also pass over there

I hope to finish the WIBY prototype soon, to make this easier and to ensure we don't break anything.

@Phillip9587
Copy link
Author

Copy link
Member

@jonchurch jonchurch left a comment

Choose a reason for hiding this comment

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

Spent a day or so reviewing, this looks solid. marking changes requested for the socket listener cleanup when msg completes first.

I considered suggesting we reuse stream.finished on the socket also, but really we only care about the close, error events there so this is fine. Socket is duplex, so we'd get the duplex handling from stream.finished unless we configured it away depending on the direction (req/res).

For anyone interested in what stream.finished is doing:
https://github.com/nodejs/node/blob/v22.15.0/lib/internal/streams/end-of-stream.js#L54

index.js Outdated
Comment on lines 23 to 24
const asyncHooks = require('node:async_hooks')
const stream = require('node:stream')
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const asyncHooks = require('node:async_hooks')
const stream = require('node:stream')
const asyncHooks = require('async_hooks')
const stream = require('stream')

Depending on the version support range we want to land on here, node:foo didn't go stable available until node 16 I think?

Copy link
Author

Choose a reason for hiding this comment

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

@jonchurch What version range do we want to support here? Since this change requires a new major release anyway, we could take the opportunity to bump the range to ">=18" to match what Express is using.

Copy link
Member

@jonchurch jonchurch May 8, 2025

Choose a reason for hiding this comment

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

cc @wesleytodd @UlisesGascon

I don't have a principled opinion here right now. The project as a whole may not either.

18 would be pragmatic, but we can get away with 10.

For context: the main reason this package is still useful IMO is that it combines the monitoring of sockets along with streams to determine when a req/res has "finished". I believe there are still some edgecases where a socket can close and the req/res would miss the close event. Hence the need to solve in libraryland vs relying solely on the platform (aka stream.finished doesn't introspect to check if the input has a socket property).

Because the change here is minor (nobody really needs this feature alone) targetting 18 has low risk of leaving someone behind.

@Phillip9587
Copy link
Author

@jonchurch I added the socket listener cleanup. Could you please take another look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants