-
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
Reduce likelihood of race conditions on keep-alive timeout calculatio… #52653
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -488,6 +488,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) { | |
socket.unref(); | ||
|
||
let agentTimeout = this.options.timeout || 0; | ||
let canKeepSocketAlive = true; | ||
|
||
if (socket._httpMessage?.res) { | ||
const keepAliveHint = socket._httpMessage.res.headers['keep-alive']; | ||
|
@@ -496,9 +497,14 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) { | |
const hint = RegExpPrototypeExec(/^timeout=(\d+)/, keepAliveHint)?.[1]; | ||
|
||
if (hint) { | ||
const serverHintTimeout = NumberParseInt(hint) * 1000; | ||
|
||
if (serverHintTimeout < agentTimeout) { | ||
// Let the timer expires before the announced timeout to reduce | ||
// the likelihood of ECONNRESET errors | ||
let serverHintTimeout = (NumberParseInt(hint) * 1000) - 1000; | ||
serverHintTimeout = serverHintTimeout > 0 ? serverHintTimeout : 0; | ||
if (serverHintTimeout === 0) { | ||
// Cannot safely reuse the socket because the server timeout is too short | ||
canKeepSocketAlive = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have updated the PR to just skip keep alive if the timeout is too short. In my local build the test now pass. |
||
} else if (!agentTimeout || serverHintTimeout < agentTimeout) { | ||
agentTimeout = serverHintTimeout; | ||
} | ||
} | ||
|
@@ -509,7 +515,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) { | |
socket.setTimeout(agentTimeout); | ||
} | ||
|
||
return true; | ||
return canKeepSocketAlive; | ||
}; | ||
|
||
Agent.prototype.reuseSocket = function reuseSocket(socket, req) { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -1010,7 +1010,9 @@ function resOnFinish(req, res, socket, state, server) { | |||||
} | ||||||
} else if (state.outgoing.length === 0) { | ||||||
if (server.keepAliveTimeout && typeof socket.setTimeout === 'function') { | ||||||
socket.setTimeout(server.keepAliveTimeout); | ||||||
// Increase the internal timeout wrt the advertised value to reduce likeliwood of ECONNRESET errors | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// due to race conditions between the client and server timeout calculation | ||||||
socket.setTimeout(server.keepAliveTimeout + 1000); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this server change is necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be the cause of all the test failures. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fix protects clients that are using the hint timeout as is (current node impl) without adjusting it for network (or cpu load) delays There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If server.keepAliveTimeout is set to 0 (never time out) this will change it to 1 second. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If server.keepAliveTimeout == 0 then the if condition line1012 is false. The timeout on the socket is set only if server.keepAliveTimeout != 0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're correct, sorry I missed that. |
||||||
state.keepAliveTimeoutSet = true; | ||||||
} | ||||||
} else { | ||||||
|
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.