-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
http2: refactor close/destroy for Http2Stream and Http2Session #17406
Conversation
b531e54
to
71d02cb
Compare
Ping @nodejs/http2 ... this should be ready for review. It's a rather large and complicated set of changes that refactors the shutdown, destroy and cleanup logic in @mcollina ... Please take a good careful look at this. |
71d02cb
to
4886232
Compare
Trying again: https://ci.nodejs.org/job/node-test-pull-request/11895/ |
Ok, there's definitely still quite a bit of wonkiness in here that I'll have to chase down. |
1912f41
to
dc812e1
Compare
I'll start reviewing this over the next few days. Might take a little while to get through. I would also like to run this against the test suite I have for express & related middleware. |
5ce9dad
to
ea67227
Compare
@apapirovski ... @mcollina and I discussed this a bit today and worked through a few more changes that need to be made (which will actually undo some of the changes made in this PR so far...). I'm working on those now and should hopefully have it complete by end of the day tomorrow at the latest. |
@jasnell No worries. Keep me posted, happy to start reviewing whenever it's ready. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good progress, I hope I reviewed all of it. Let me know if I missed some critical changes.
lib/internal/http2/core.js
Outdated
@@ -66,10 +66,11 @@ const TLSServer = tls.Server; | |||
const kInspect = require('internal/util').customInspectSymbol; | |||
|
|||
const kAuthority = Symbol('authority'); | |||
const kDestroySocket = Symbol('destroy-socket'); | |||
const kErrorEmitted = Symbol('error-emitted'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this used at all?
lib/internal/http2/core.js
Outdated
owner[kUpdateTimer](); | ||
process.nextTick(emit, owner, 'error', error); | ||
if (state.fd !== undefined) | ||
fs.close(state.fd, () => {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we swallowing an error here? Can we destroy those in parallel safely?
lib/internal/http2/core.js
Outdated
// indicate if the ping was successful or not. The duration indicates the | ||
// number of milliseconds elapsed since the ping was sent and the ack | ||
// received. The payload is a Buffer containing the 8 bytes of payload | ||
// data received on the PING acknowlegement. | ||
function pingCallback(cb) { | ||
return function(ack, duration, payload) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you name this function?
lib/internal/http2/core.js
Outdated
|
||
session.settings(settings); | ||
process.nextTick(emit, session, 'connect', session, socket); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lot of code that is kind of hot. This should live in a top level function somewhere. Can we remove the need to wrap it in a closure?
lib/internal/http2/core.js
Outdated
if (state.shutdown || state.shuttingDown) | ||
// Destroy the Http2Session, making it no longer usable and cancelling | ||
// any pending activity. | ||
destroy(error = NGHTTP2_NO_ERROR, code, lastStreamID, opaqueData) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need all these arguments? I would really prefer we did a .destroy(err, callbak)
, where err
is an instance of Error
. It seems this signature is one for a more internal function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the lastStreamID
and opaqueData
here.. I've removed those. The code
is required because we have to know which error code to send in the final GOAWAY frame and that cannot always be determined automatically.
// case, drop the data on the floor. An error should have already been | ||
// emitted. | ||
if (this.destroyed) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should not be needed, why it is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above :-)
// the Http2Stream to be closed and ultimately destroyed. After calling | ||
// close, it is still possible to queue up PRIORITY and RST_STREAM frames, | ||
// but no DATA and HEADERS frames may be sent. | ||
close(code = NGHTTP2_NO_ERROR, callback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be close(callback)
? I would prefer to not expose NGHTTP2 error codes. For errors, we have destroy()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not an NGHTTP2 error code, it's an HTTP2 RST_STREAM error code. An RST_STREAM is used to close the stream here so we need to know what code to use. There are legitimate cases where the user might specify something other than NO_ERROR
without using destroy(err)
lib/internal/http2/core.js
Outdated
return; | ||
} | ||
if (err) { | ||
process.nextTick(emit, this, 'error', err); | ||
if (this.destroyed || this.closed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this can happen? I think a comment is needed
lib/internal/http2/core.js
Outdated
process.nextTick(emit, this, 'error', err); | ||
if (this.destroyed || this.closed) { | ||
// TODO(jasnell): emit error here instead? | ||
abort(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
silently ignoring things is not nice, I'd do the error here.
lib/internal/http2/core.js
Outdated
if (!Array.isArray(headersList)) { | ||
process.nextTick(emit, this, 'error', headersList); | ||
if ((typeof options.statCheck === 'function' && | ||
options.statCheck.call(this, stat, headers, statOptions) === false) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a comment explaining this condition?
44548d5
to
c288dee
Compare
9bbf47e
to
a2f5486
Compare
@jasnell Can you give an overview over what’s going to happen with this PR? Is it (nearly) ready? :) And maybe, are the C++ bits independent enough from the rest that they could be split off into their own PR? I’ll continue working on |
This pr is nearly there. Working on getting one final test working then will be squashing and reorganizing the commits down. Unfortunately, no, the c++ bits cannot be spun off into their own pr. The goal is to get this finished up today. |
lib/internal/http2/compat.js
Outdated
callback(err); | ||
return; | ||
} | ||
callback(err, new Http2ServerResponse(stream)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you replace err
as null
?
PR-URL: nodejs#17406 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Backport-PR-URL: nodejs#18050
Backport-PR-URL: nodejs#18050 PR-URL: nodejs#17406 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> This is a significant cleanup and refactoring of the cleanup/close/destroy logic for Http2Stream and Http2Session. There are significant changes here in the timing and ordering of cleanup logic, JS apis. and various related necessary edits.
Refs: nodejs#17406 (comment) PR-URL: nodejs#18088 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Improve documentation of callback signature of http2Stream.pushStream() function to align with the changes made in nodejs#17406. PR-URL: nodejs#18258 Fixes: nodejs#18198 Refs: nodejs#17406 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Backport-PR-URL: #18050 Backport-PR-URL: #20456 PR-URL: #17406 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> This is a significant cleanup and refactoring of the cleanup/close/destroy logic for Http2Stream and Http2Session. There are significant changes here in the timing and ordering of cleanup logic, JS apis. and various related necessary edits.
Refs: #17406 (comment) Backport-PR-URL: #20456 PR-URL: #18088 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Improve documentation of callback signature of http2Stream.pushStream() function to align with the changes made in nodejs#17406. PR-URL: nodejs#18258 Fixes: nodejs#18198 Refs: nodejs#17406 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
The old error code `ERR_HTTP2_STREAM_CLOSED` was removed in commit 0babd18 (pull request nodejs#17406), and the testcase for http2stream.pushStream was changed accordingly, but the documentation change was overlooked. This commit fixes it and aligns the documentation with the testcase. This is a part of the fixes hinted by nodejs#21470, which includes some tests for error codes usage and documentation and enforces a stricter format. Refs: nodejs#21470 Refs: nodejs#17406 PR-URL: nodejs#21487 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
The old error code `ERR_HTTP2_STREAM_CLOSED` was removed in commit 0babd18 (pull request #17406), and the testcase for http2stream.pushStream was changed accordingly, but the documentation change was overlooked. This commit fixes it and aligns the documentation with the testcase. This is a part of the fixes hinted by #21470, which includes some tests for error codes usage and documentation and enforces a stricter format. Refs: #21470 Refs: #17406 PR-URL: #21487 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
The old error code `ERR_HTTP2_STREAM_CLOSED` was removed in commit 0babd18 (pull request nodejs#17406), and the testcase for http2stream.pushStream was changed accordingly, but the documentation change was overlooked. This commit fixes it and aligns the documentation with the testcase. This is a part of the fixes hinted by nodejs#21470, which includes some tests for error codes usage and documentation and enforces a stricter format. Refs: nodejs#21470 Refs: nodejs#17406 PR-URL: nodejs#21487 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
The old error code `ERR_HTTP2_STREAM_CLOSED` was removed in commit 0babd18 (pull request nodejs#17406), and the testcase for http2stream.pushStream was changed accordingly, but the documentation change was overlooked. This commit fixes it and aligns the documentation with the testcase. This is a part of the fixes hinted by nodejs#21470, which includes some tests for error codes usage and documentation and enforces a stricter format. Refs: nodejs#21470 Refs: nodejs#17406 PR-URL: nodejs#21487 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
The old error code `ERR_HTTP2_STREAM_CLOSED` was removed in commit 0babd18 (pull request nodejs#17406), and the testcase for http2stream.pushStream was changed accordingly, but the documentation change was overlooked. This commit fixes it and aligns the documentation with the testcase. This is a part of the fixes hinted by nodejs#21470, which includes some tests for error codes usage and documentation and enforces a stricter format. Refs: nodejs#21470 Refs: nodejs#17406 PR-URL: nodejs#21487 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
The old error code `ERR_HTTP2_STREAM_CLOSED` was removed in commit 0babd18 (pull request #17406), and the testcase for http2stream.pushStream was changed accordingly, but the documentation change was overlooked. This commit fixes it and aligns the documentation with the testcase. This is a part of the fixes hinted by #21470, which includes some tests for error codes usage and documentation and enforces a stricter format. Refs: #21470 Refs: #17406 Backport-PR-URL: #22850 PR-URL: #21487 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This is a significant refactoring of the close/destroy flow and API for
Http2Stream
andHttp2Session
. There is quite a bit more to do in here, it's a bit slow going because the flow is rather complex and I'm trying not to break too much as I go.There are several important bits:
Previously, the destroy operations for both
Http2Session
andHttp2Stream
were executed over multiple nextTick and setImmediate hops. Now the objects are unusable immediately when callingdestroy()
and we're usingenv->SetImmediate()
to handle the need to defer final cleanup (cc @addaleax)This reworks the destroy and error handling flow between the
Http2Session
and socket and eliminates the'socketError'
event. Errors occurring on the socket are forwarded to the error event on the associatedHttp2Session
. On the server, those are forwarded to the'sessionError'
event.Http2Stream.prototype.rstStream()
has been renamed toHttp2Stream.prototype.close()
and the variousrstWith....
aliases have been removed.An improved
Http2Session.prototype.close()
has been implemented, allowing better API symmetry.There are still a few more todo's that need to be handled here. Specifically, proper handling of last stream ID on a goaway frame, but this is already a sizable chunk of work. Let's get this reviewed and landed and I'll keep pushing forward.
/cc @nodejs/http2
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
http2