-
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
http: fixed socket destruction, timeout and leaking #2534
Conversation
lib/_http_server.js
Outdated
@@ -447,20 +448,25 @@ function connectionListener(socket) { | |||
// if the user never called req.read(), and didn't pipe() or | |||
// .resume() or .on('data'), then we call req._dump() so that the | |||
// bytes will be pulled off the wire. | |||
if (!req._consuming && !req._readableState.resumeScheduled) |
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.
Unnecessary style fixes.
This PR changes the expectations of at least one test without changing anything else in that test. Does it make this PR a |
This expectation https://github.com/tshemsedinov/io.js/blob/master/test/sequential/test-http-pipeline-flood.js#L51 based on wrong behavior, when |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
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.
Please remove this license boilerplate. The necessary licensing can already be found in the LICENSE file.
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.
Removed
issue: nodejs/node#2534 crutch from: http://habrahabr.ru/post/264851/ Signed-off-by: Oleg Verych <ole4at@gmail.com>
lib/_http_server.js
Outdated
|
||
res.detachSocket(socket); | ||
res._last = outgoing.length === 0; |
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 is this required?
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.
Because in this place _last is not calculated, so when length is 0, _last is not true and res will not processed as last.
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 it is not calculated because the res might be not the last here?
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.
In debugging I found that when res was last in outgoing
, and _last
flag is not correct, but we need it calculated correctly for next lenes, to destroy socket if it is last.
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.
Again, it should be a separate clause for this thing. _last
indicates that there are not going to be any requests on the TCP socket. While there definitely could be in case of outgoing.length === 0
.
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 checking that on res:finish
event, why it is not a right place to detect "is outgoing queue is empty?" In this place res._last
inicates that we have no nore message to send.
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.
Because we should destroy the socket immediately when the connection wasn't keep-alive, or when TCP connection has already ended.
@tshemsedinov : decided to do a proper write up, instead of in-line comments. I like the idea of PR, but I think the way it interacts with existing logic could be potentially buggy.
Instead of using it for different purpose, I suggest to do it without property it all. If there are no pending requests - let's call Thanks for submitting this! |
Of course we can check outgoing queue and not changing |
@tshemsedinov there are lots of irrelevant style changes through the PR, ditto means "here too". Please change only the parts of code that are relevant to this behavior change. Also, there are some style issues (mostly 80 column limit). |
Thanks! |
lib/_http_server.js
Outdated
@@ -482,8 +483,15 @@ function connectionListener(socket) { | |||
|
|||
res.detachSocket(socket); | |||
|
|||
if (res._last) { | |||
socket.destroySoon(); | |||
if (res._last) socket.destroySoon(); |
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 found problem with non keep-alive sockets and here is fix for this case. @indutny, finally _last
in it's untouched state is useful to detect non keep-alive sockets and destroy them as it was before this changes. Now all tests completed successfully.
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.
Cool!
@ChALkeR : a bit premature? Maybe cancel? |
@indutny He asked for it, why not? Most machines are free. |
Wow, I think this wasn't a successful force-push :/ |
That was strange, but I've reopened the PR and the commit is here, great. |
I wanted to trigger a fresh CI run on this, but something got really borked with this PR and
|
Yay, everything works fine after another force-push. CI: https://ci.nodejs.org/job/node-test-pull-request/8282/ I've made some changes to the docs, namely: YAML header with the "added:" metadata, cross-links between the |
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.
Documentation generally LGTM.
Just a few nits and lite rephrasing
doc/api/http.md
Outdated
@@ -841,8 +841,25 @@ Note that the socket timeout logic is set up on connection, so | |||
changing this value only affects *new* connections to the server, not |
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.
Aren't these two bulleted list notes?
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'd rather not change it in this PR, it would be an unrelated stylistic change. But yeah, a nice thing to do in a follow-up PR.
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.
Ah, never mind. I changed the server.timeout
docs for consistency anyway.
doc/api/http.md
Outdated
@@ -841,8 +841,25 @@ Note that the socket timeout logic is set up on connection, so | |||
changing this value only affects *new* connections to the server, not | |||
any existing connections. | |||
|
|||
Set to 0 to disable any kind of automatic timeout behavior on incoming | |||
connections. | |||
Set to 0 to disable timeout behavior on incoming connections. |
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.
[Suggestion] /s/Set to 0 to disable/A value of 0 will disable
P.S. what does it mean? Sockets will be destroyed ASAP, or timeout is delegated to OS?
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 latter option, roughly speaking. It will just disable any Node-specific timeout logic.
doc/api/http.md
Outdated
Set to 0 to disable any kind of automatic timeout behavior on incoming | ||
connections. | ||
Set to 0 to disable timeout behavior on incoming connections. | ||
If `server.timeout` is not 0 and [`server.keepAliveTimeout`][] is 0, |
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.
IMHO you can simplify to just If [`server.keepAliveTimeout`][] is 0, the value of `server.timeout` will be used instead.
And now it's a Note: for server.keepAliveTimeout
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... or, maybe, even better to drop this sentence completely? It's not exactly accurate.
doc/api/http.md
Outdated
added: REPLACEME | ||
--> | ||
|
||
* {Number} Defaults to 5000 (5 seconds). |
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.
* {Number} Timeout in milliseconds. Defaults to 5000.
doc/api/http.md
Outdated
|
||
* {Number} Defaults to 5000 (5 seconds). | ||
|
||
The number of milliseconds of inactivity after a server has finished writing |
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 number of milliseconds of inactivity the server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed.
doc/api/http.md
Outdated
socket will be destroyed. | ||
|
||
If the server receives new data before the keep-alive timeout has fired, it | ||
will renew the regular inactivity timeout, i.e., [`server.timeout`][]. |
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.
/s/renew/reset/
@refack thanks! I've made some amendments, can you please take another look? |
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.
Docs LGTM.
Rubberstamp the code.
doc/api/http.md
Outdated
|
||
The number of milliseconds of inactivity a server needs to wait for additional | ||
incoming data, after it has finished writing the last response, before a socket | ||
will be destroyed. |
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.
Tiny nit.
IMHO These two paragraphs could now be merged (the sentences have the same subject, so they could follow each other naturally)
very low importance on this
@jasnell as far as I see from the notifications, you're on GitHub now 😄 Can you please take a look at the latest changes while you are here? Thanks! |
Implement server.keepAliveTimeout in addition to server.timeout to prevent temporary socket/memory leaking in keep-alive mode.
Squashed and rebased onto master again. I'd like to land it today or tomorrow. |
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.
CITGM clean.
Implement server.keepAliveTimeout in addition to server.timeout to prevent temporary socket/memory leaking in keep-alive mode. PR-URL: #2534 Author: Timur Shemsedinov <timur.shemsedinov@gmail.com> Author: Alexey Orlenko <eaglexrlnk@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com>
Landed in 0aa7ef5 🎉 |
Implement server.keepAliveTimeout in addition to server.timeout to prevent temporary socket/memory leaking in keep-alive mode. PR-URL: #2534 Author: Timur Shemsedinov <timur.shemsedinov@gmail.com> Author: Alexey Orlenko <eaglexrlnk@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com>
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for nodejsGH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: nodejs#2534 Fixes: nodejs#13391
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for GH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-client-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: #2534 Fixes: #13391 PR-URL: #13549 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for GH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-client-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: #2534 Fixes: #13391 PR-URL: #13549 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for GH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-client-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: #2534 Fixes: #13391 PR-URL: #13549 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
Release team decided not to backport to v6.x. Comment if you would like it to be backported. |
res._last
, because it was not calculated correctly in this place before this PR and as a resultsocket.destroySoon()
was never executedserver.keepAliveTimeout
(default to 5 seconds) in addition toserver.timeout
timeout
event on server for finished and closed socketssocket.destroySoon()
because it worked well onprefinish
and have no sense onfinish
Memory usage comparison before and after:
Socket handlers usage comparison before and after:
Tests changed and provided new.
Related PR: #1411 by @indutny
Related Issue: nodejs/node-v0.x-archive#3460
Article about this problem (RU): http://habrahabr.ru/post/264851/