-
Notifications
You must be signed in to change notification settings - Fork 30k
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
net/http2: use actual Timeout instances #17704
net/http2: use actual Timeout instances #17704
Conversation
Ok so it looks like the @nodejs/http team is somewhat outdated so... maybe let's try @nodejs/http2 and see if anyone there has an idea of what's up. 🙃 |
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.
net
module, timeouts, a broken test … sounds like the perfect thing for @apapirovski to take a look at 🙃
I’ll try to look at the failure myself though.
@@ -381,14 +387,36 @@ Socket.prototype.read = function(n) { | |||
}; | |||
|
|||
Socket.prototype.setTimeout = function(msecs, callback) { | |||
// Type checking identical to timers.enroll() |
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 might be enough code to factor it out into some internal function, wdyt?
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.
Might be a good idea yeah.
I think this PR may break the "mysql" module. I want to run the test suite, but not sure on the process. I assume this change won't be in a prebuilt nightly until it is merged, is that right? |
Correct. You'd need to build your own version of node probably. I could do an "RC" with it technically but I'm not super familiar with that process. @dougwilson Is "mysql" in citgm? |
I don't see it listed. Not sure if it qualifies to be in there or not. I've looked around through the changes and how mysql is using the timers and I don't think it will be an issue. I was thinking it hooked into the socket timers but I think it is using the timers on it's own objects. I'll build a copy, no worries 👍 |
Ok, extracted the type checking. Not quite sure how that commit triggered it but it seems to have exposed that I also need to update the patch to include HTTP/2... |
Here’s a There do appear to be some errors related to domains/async tracking in there… |
@addaleax It appears that already occurs on |
To be fair, that test is pretty brittle... assert.equal(domain.active, null, 'query is not bound to domain'); Not sure we have any responsibility there. |
I've never used domains and am not familiar. Domain support was contributed to the module a long time ago. What should the test be instead? |
@dougwilson I'm looking into this more, after running it a few times, I don't think it's related to what I had initially thought. Will update when I have more info. |
Added an http2 patch. I REALLY wish manual timers were never used there. We should probably just ban using New CI: https://ci.nodejs.org/job/node-test-pull-request/12154/ |
lib/internal/http2/core.js
Outdated
if (msecs === 0) { | ||
unenroll(this); | ||
clearTimeout(this[kTimeout]); | ||
|
||
if (callback !== undefined) { |
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.
I feel like these conditionals are probably not how the API should work, but I'll leave that for another PR.
lib/internal/http2/core.js
Outdated
this[kTimeout] = setUnrefTimeout(() => { | ||
this._onTimeout(); | ||
}, msecs); | ||
if (this[kSession]) this[kSession][kUpdateTimer](); |
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.
Seems messy but it doesn't seem like [kUpdateTimer]
should create new timers? 😕
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.
Maybe this is actually a bug? @jasnell should HTTP2Stream#setTimeout()
create a new timeout on the session, if there is a session?
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.
@Fishrock123 that line is to differentiate between HTTP2Stream and HTTP2Session, as this code is attached to both prototypes.
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.
Understood, but why refresh the session timer from the stream with it's existing timeout? Is that really intended from here without updating the session's timeout duration to a potential new duration?
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.
The session timeout needs to be refreshed every time any of the associated streams moves data, as the socket is there.
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.
LGTM
dbfcce7
to
c396b24
Compare
OK, I fixed the http tests issue. Turns out I was leaking timeouts but that should be fixed now by clearing an existing timeout before creating a new one. |
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 great! 👍
lib/internal/http2/core.js
Outdated
this[kUpdateTimer](); | ||
clearTimeout(this[kTimeout]); | ||
this[kTimeout] = setUnrefTimeout(() => { | ||
this._onTimeout(); |
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 won't be feasible for http
but for http2
, I think we could move this off the publicly available _onTimeout
and instead onto a Symbol.
Also, I would prefer if this was bound instead of using an arrow function but that's just a minor nit.
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.
Prefer that to be done in a separate commit. I'll switch to bind()
, IIRC perf was good enough now?
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.
Prefer that to be done in a separate commit.
I figured it could go here since this PR is what enables us to no longer use a publicly exposed method but either way works for me. 👍
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.
Hmm, true. Not sure how I feel about it.
lib/net.js
Outdated
if (msecs === 0) { | ||
timers.unenroll(this); | ||
clearTimeout(this[kTimeout]); |
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 we just move this outside of the condition since it's in both branches?
lib/internal/http2/core.js
Outdated
this[kTimeout] = setUnrefTimeout(() => { | ||
this._onTimeout(); | ||
}, msecs); | ||
if (this[kSession]) this[kSession][kUpdateTimer](); |
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.
Does this actually need the conditional? Couldn't it just call this[kUpdateTimer]();
like before?
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.
that if (this[kSession])
is roughly equal to if (this instanceof HTTP2Stream)
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.
It just seems like we could just straight up call this[kUpdateTimer]()
since it has the same check in it. If this is about avoiding the _unrefActive
then this call could just be moved before this[kTimeout]
is declared.
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.
What if there is no session then?
There is no point in calling this[kUpdateTimer]();
on the Stream - you'll just insert the stream timer twice... Might as well move the extra conditional bit here.
A sort-of follow-up to nodejs#17704, this removes the last internal use of enroll().
A sort-of follow-up to nodejs#17704, this removes the last internal use of enroll(). PR-URL: nodejs#17800 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
A sort-of follow-up to #17704, this removes the last internal use of enroll(). PR-URL: #17800 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
A sort-of follow-up to #17704, this removes the last internal use of enroll(). PR-URL: #17800 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
@Fishrock123 Did you have a plan to backport parts of this? I noticed #18062 and #18065 depend on some of the changes here, including the fact that there's a new There are also follow up PRs that landed since that aren't I would be happy to help, if needed. |
No, I don’t really have time to do backports... |
No worries. I'll try to figure out a way we can get this backported. I assume we should be able to do it if we just exclude the |
A bug was introduced in nodejs#17704 which meant that subsequent calls to enroll would unset the new _idleTimeout and the enrolled object could never again function as a timer.
A bug was introduced in #17704 which meant that subsequent calls to enroll would unset the new _idleTimeout and the enrolled object could never again function as a timer. PR-URL: #19936 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
A bug was introduced in #17704 which meant that subsequent calls to enroll would unset the new _idleTimeout and the enrolled object could never again function as a timer. PR-URL: #19936 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
timers, net
This PR is a re-made version of #11154
This makes
net.Socket
s,Http2Stream
s, andHttp2Session
s use actualTimeout
objects in a[kTimeout]
symbol property, rather than making the socket/stream/session itself a timer and appending properties to it directly.This should make the code generally easier to understand, and might also prevent some deopts from properties being changes on the socket itself.
It is possible this could minorly effect performance either better or worse, but benchmarks on
net.Socket
from #11154 showed little difference.This also moves some of the Timeout prototype into the internal file but not all of it, perhaps we can do that in a later commit if desirable.
New: Also exposes a timer duration validation function, using
enroll()
's validation logic.Unfortunately, sometime in the past few months some HTTP change occured that I haven't been able to get past, so two tests fail.😕This change somehow causes aclientError
to be emitted in bothtest-http-server-keep-alive-timeout-slow-client-headers
andtest-http-server-keep-alive-timeout-slow-server
... I added the extra temporary patch to help debug those. It seems to fail to parse the request chunk... somehow.Hopefully @nodejs/http can help...Test failure output in the fold
CI (going to fail): https://ci.nodejs.org/job/node-test-pull-request/12145/