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
fix(server): address Node v10.x req close event firing order #1672
Changes from 1 commit
929f9a1
b237d3e
99bc0bf
c54c3c1
5996573
245a91d
f82c3a6
b84caa8
4e8e5de
6cb9fc7
ee3b338
df356c9
10410fb
def6164
3d0bd42
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 |
---|---|---|
|
@@ -1143,19 +1143,37 @@ Server.prototype._setupRequest = function _setupRequest(req, res) { | |
// the connection (or we lose the connection). | ||
// we consider a closed request as flushed from metrics point of view | ||
function onClose() { | ||
res._flushed = true; | ||
req._timeFlushed = process.hrtime(); | ||
|
||
res.removeListener('finish', onFinish); | ||
res.removeListener('error', onError); | ||
|
||
req._connectionState = 'close'; | ||
|
||
// Do no handle close if request is already flushed | ||
// In Node >= 10 res's close event is always emitted | ||
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. Is is Node > 10.4.0 at least? It seems that change hasn't been made it to any release yet. 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 seems to be working with all supported Node.js versions, 6,8 10.0.0 and 10.4.0 as well. |
||
// Introduced in: https://github.com/nodejs/node/pull/20611 | ||
if (res._flushed) { | ||
return; | ||
} | ||
|
||
// Handle close and return error if request is not flushed yet | ||
res._flushed = true; | ||
req._timeFlushed = process.hrtime(); | ||
|
||
// Request was aborted or closed. Override the status code | ||
res.statusCode = 444; | ||
|
||
self._finishReqResCycle(req, res, new errors.RequestCloseError()); | ||
self._finishReqResCycle( | ||
req, | ||
res, | ||
res.err || new errors.RequestCloseError() | ||
); | ||
} | ||
req.once('close', onClose); | ||
|
||
// Handle res's close on to the next cycle | ||
// Required in Node >= 10: | ||
// introduced in: https://github.com/nodejs/node/pull/20941 | ||
req.once('close', function onReqClose() { | ||
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. Is it that because res' It seems this ordering could break if .e.g node started emitting the res' 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. Yes, what would you recommend to make it more robust? |
||
setImmediate(onClose); | ||
}); | ||
|
||
// Response lifecycle events | ||
function onFinish() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1924,8 +1924,12 @@ test("should emit 'after' on successful request", function(t) { | |
}); | ||
|
||
SERVER.get('/foobar', function(req, res, next) { | ||
res.send('hello world'); | ||
next(); | ||
setTimeout(function() { | ||
res.send('hello world'); | ||
setTimeout(function() { | ||
next(); | ||
}, 500); | ||
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. Why do we need any 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. We generate some "work" in the server to be sure that events are firing in the right order. In my previous fix tests passed with positive 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.
EDIT: I get it now: we want to send the response and call the Why not keeping the original test? Should be add a new test instead of replacing the existing one? 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. Remaining questions above still relevant:
|
||
}, 500); | ||
}); | ||
|
||
CLIENT.get('/foobar', function(err, _, res) { | ||
|
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.
Typo "Do 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.
Also, is it "if response is already flushed" here, or do we mean "request" in the sense of "the whole request/response"? I think it'd help to distinguish between request and response here for clarity, and in this case it seems we're checking if the response is flushed.
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.
good catch!