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

Undocumented breaking change on v16.0.0 #38924

Closed
mmarchini opened this issue Jun 4, 2021 · 19 comments · Fixed by #42521
Closed

Undocumented breaking change on v16.0.0 #38924

mmarchini opened this issue Jun 4, 2021 · 19 comments · Fixed by #42521
Labels
doc Issues and PRs related to the documentations. http Issues or PRs related to the http subsystem.

Comments

@mmarchini
Copy link
Contributor

  • Version: v16.0.0
  • Platform: OS X
  • Subsystem: http

What steps will reproduce the bug?

  1. Save the script below as index.js and run it.
'use strict'
const http = require('http');

const requestListener = function (req, res) {
  req.on('data', () => {});

  req.once('end', () => {
    console.log(1);
  });

  req.once('close', () => {
    console.log(2);
  });
}

const server = http.createServer(requestListener);
server.listen(8080);
  1. Run curl localhost:8080

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

Always

What is the expected behavior?

Prior to v16, the server would print the output below and hang.

$ node index.js
1

What do you see instead?

On v16, the server prints the output below and hang.

$ node index.js
1
2

On both cases curl doesn't exit while waiting for a response. Note that 2 is being called because close is being emitted even though the connection is not closed yet. I'm not sure if that is intended behavior or not, but I couldn't find anything in the changelog suggesting this was an intentional change. Furthermore, it's a breaking change and it should be documented as such.

Additional information

The example above is an overly simplification of a situation I've stumbled upon while investigating failing restify tests on Node.js v16. The failing test in question is this, and the failure happens because restify expects close to only be called when the connection closes.

@lpinca lpinca added the http Issues or PRs related to the http subsystem. label Jun 4, 2021
@mscdex
Copy link
Contributor

mscdex commented Jun 4, 2021

I would guess that the 'close' event is specific to the request stream and not the underlying socket.

@mmarchini
Copy link
Contributor Author

From http.IncomingMessage close documentation:

Event: 'close'

Added in: v0.4.2

Indicates that the underlying connection was closed.

So the (documented) intention is not that the stream was closed, but the underlying [socket] connection. That's still our documentation on v16, which makes me think this might've been an unintentional change. cc @nodejs/tsc @nodejs/http

@ronag
Copy link
Member

ronag commented Jun 4, 2021

The current behavior is correct per se and totally intentional to be compliant with streams. I would rather update the documentation which is wrong IMO.

The old behavior basically means that using it in a streams api is undefined behavior from the user’s perspective.

@mmarchini
Copy link
Contributor Author

It needs to be both documented as a breaking change in our changelogs and the documentation needs to be updated then. Right now this is a breaking change that is not documented anywhere. In which PR was it introduced?

@ghermeto
Copy link

ghermeto commented Jun 4, 2021

I just added a comment before here thinking this was a breaking change on a minor... 😳

Don't mind me...

@targos
Copy link
Member

targos commented Jun 5, 2021

If we don't find the PR which introduced the change, it might land soon by mistake on v14.x.

@ronag
Copy link
Member

ronag commented Jun 5, 2021

I’m pretty sure the Pr was semver. Can’t find it at the moment. Will look a bit more tonight.

@ronag
Copy link
Member

ronag commented Jun 5, 2021

Wait. This is on IncomingMessage which is a Readable. I’m very surprised if the behavior is different on node 14.

@ronag
Copy link
Member

ronag commented Jun 5, 2021

It might be doe autoDestroy true change we did.

@targos
Copy link
Member

targos commented Jun 5, 2021

It might be doe autoDestroy true change we did.

Do you mean #33035 ?
It was reverted in #36647 before the release of v16.0.0

@ronag
Copy link
Member

ronag commented Jun 5, 2021

It was only reverted on v15 and then made it into v16 as a semver major. I think the fix here is docs and maybe missing in change log.

@targos
Copy link
Member

targos commented Jun 5, 2021

Oh I see, it was actually landed initially as semver-minor.
Our release tooling is not capable of detecting that a change was retroactively marked major. I agree the fix is to update the docs (add a "changes" entry somewhere)

@targos
Copy link
Member

targos commented Jun 5, 2021

Our release tooling is not capable of detecting that a change was retroactively marked major.

It's not only about major changes. If something lands on master, is released on some version, and is then reverted only on a release branch, the next major is not going to have this change in its changelog.

@aduh95 aduh95 added the doc Issues and PRs related to the documentations. label Jun 10, 2021
@mmarchini mmarchini changed the title Undocumented(?) breaking change on v16.0.0 Undocumented breaking change on v16.0.0 Jun 22, 2021
mmarchini added a commit to mmarchini/node-restify that referenced this issue Sep 29, 2021
The close event from the request object is not guaranteed to fire on the
same order across major versions of Node.js, the more accurate way to
look if the connection was closed is to listen to the event on the
socket. Fixes tests on v16.

Ref: nodejs/node#38924
mmarchini added a commit to restify/node-restify that referenced this issue Sep 29, 2021
The close event from the request object is not guaranteed to fire on the
same order across major versions of Node.js, the more accurate way to
look if the connection was closed is to listen to the event on the
socket. Fixes tests on v16.

Ref: nodejs/node#38924
mmarchini added a commit to restify/node-restify that referenced this issue Sep 29, 2021
The close event from the request object is not guaranteed to fire on the
same order across major versions of Node.js, the more accurate way to
look if the connection was closed is to listen to the event on the
socket. Fixes tests on v16.

Ref: nodejs/node#38924
rudolf added a commit to jbudz/kibana that referenced this issue Oct 11, 2021
jbudz added a commit to elastic/kibana that referenced this issue Oct 16, 2021
* Bump node to ^16

* fix comment

* use jest timers

* bump mock-fs

* Fix core type errors

* Unskipping tests that work on my machine

* skip new unhandled promise rejection

* Fix Nodejs v16 regression due to nodejs/node#38924

* Fix failing concurrent connections collector test

* Fix types after merge from master

* update servicenow test

* Skip unhandledRejection tests

* Skip tests with unhandled promise rejection

* Fix discover jest failures

* bump node to 16.11.1

* revert timeout increase

* skip unhandled promise rejection

* rm jest import

* skip unhandled promise rejection

Co-authored-by: Rudolf Meijering <skaapgif@gmail.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Tim Roes <tim.roes@elastic.co>
@Prinzhorn
Copy link

Prinzhorn commented Dec 29, 2021

I've just run into this as well (and this is not the only issue that has been opened for this exact breaking change). I'm using the close event to abort an AbortController to cancel tasks (e.g. in a worker via Piscina) when the client stops the request (e.g. a "Cancel" button in the UI abort()s the fetch on the client, which propagates all the way and cancels the task on the server, similar to Context in Go).

I don't think I can listen to close on socket, because of HTTP/2 (a socket does not correlate to a single request/response cycle) or even just because of Keep-Alive in HTTP/1.1? Where can I override autoDestroy, if at all (I'm using fastify)? Or is there any other reliable way to do what I'm doing in Node.js 16+?

Edit: nvm, I guess listening for the socket close seems to do what I need with some tweaking.

@ShogunPanda
Copy link
Contributor

ShogunPanda commented Mar 21, 2022

I think nothing else is needed on this. Can we close the issue?

@mmarchini
Copy link
Contributor Author

I don't think the docs and changelogs were updated with the new behavior yet (unless I missed it).

@ShogunPanda
Copy link
Contributor

Oh, I missed that. I'll take care of it.
Just to clarify, the change is that on IncomingMessage the close event is emitted when a HTTP request is finished and not (like in was in the past) when the underlying socket is closed. Am I right?

aduh95 pushed a commit that referenced this issue Apr 1, 2022
PR-URL: #42521
Fixes: #38924
Refs: #33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
juanarbol pushed a commit to juanarbol/node that referenced this issue Apr 5, 2022
PR-URL: nodejs#42521
Fixes: nodejs#38924
Refs: nodejs#33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
juanarbol pushed a commit that referenced this issue Apr 6, 2022
PR-URL: #42521
Fixes: #38924
Refs: #33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
xtx1130 pushed a commit to xtx1130/node that referenced this issue Apr 25, 2022
PR-URL: nodejs#42521
Fixes: nodejs#38924
Refs: nodejs#33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
juanarbol pushed a commit that referenced this issue May 31, 2022
PR-URL: #42521
Fixes: #38924
Refs: #33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
danielleadams pushed a commit that referenced this issue Jun 27, 2022
PR-URL: #42521
Fixes: #38924
Refs: #33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
targos pushed a commit that referenced this issue Jul 11, 2022
PR-URL: #42521
Fixes: #38924
Refs: #33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
guangwong pushed a commit to noslate-project/node that referenced this issue Oct 10, 2022
PR-URL: nodejs/node#42521
Fixes: nodejs/node#38924
Refs: nodejs/node#33035
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Beth Griggs <bgriggs@redhat.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
@Fabioni
Copy link

Fabioni commented Nov 14, 2024

I've just run into this as well (and this is not the only issue that has been opened for this exact breaking change). I'm using the close event to abort an AbortController to cancel tasks (e.g. in a worker via Piscina) when the client stops the request (e.g. a "Cancel" button in the UI abort()s the fetch on the client, which propagates all the way and cancels the task on the server, similar to Context in Go).

I don't think I can listen to close on socket, because of HTTP/2 (a socket does not correlate to a single request/response cycle) or even just because of Keep-Alive in HTTP/1.1? Where can I override autoDestroy, if at all (I'm using fastify)? Or is there any other reliable way to do what I'm doing in Node.js 16+?

Edit: nvm, I guess listening for the socket close seems to do what I need with some tweaking.

@Prinzhorn What was the tweaking you did to make this working reliably?

@Prinzhorn
Copy link

@Fabioni I only needed this to work in a specific environment (Electron + HTTP/1.1). Take a look at the implementation of https://www.npmjs.com/package/fastify-racing for a more general approach

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations. http Issues or PRs related to the http subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants