Skip to content
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

feat: provide callback to uncaughtException handler #1766

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion lib/server.js
Expand Up @@ -1405,7 +1405,16 @@ Server.prototype._routeErrorResponse = function _routeErrorResponse(
self.handleUncaughtExceptions &&
self.listenerCount('uncaughtException') > 1
) {
self.emit('uncaughtException', req, res, req.route, err);
self.emit(
'uncaughtException',
req,
res,
req.route,
err,
function uncaughtExceptionCompleted() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put a comment about the why here and describe what will happen with and without domains.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hekike @rajatkumar Added some comments here, let me know if that addresses your feedback!

self._finishReqResCycle(req, res, err);
}
);
return;
}

Expand Down
28 changes: 28 additions & 0 deletions test/server.test.js
Expand Up @@ -2051,6 +2051,34 @@ test(
}
);

// eslint-disable-next-line max-len
test("should emit 'after' on client closed request with an uncaughtException", function(t) {
SERVER.on('after', function(req, res, route, err) {
t.ok(err);
t.equal(req.connectionState(), 'close');
t.equal(res.statusCode, 444);
t.equal(err.name, 'Error');
t.end();
});

SERVER.on('uncaughtException', function(req, res, route, err, next) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the documentation, I would suggest not calling that callback next, so that users don't confuse this callback with middlewares' next callbacks and their specific semantics/API.

next();
});

SERVER.get('/foobar', function(req, res, next) {
// fast client times out at 500ms, wait for 800ms which should cause
// client to timeout
setTimeout(function() {
throw new Error('foo');
}, 800);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rely on a 'timeout' event on FAST_CLIENT instead of a timer duration to make sure that we throw after the client times out and abort the request? Or maybe even relying on an abort event on the client would be better? Or even better on the 'abort' event of the request object?

Otherwise it seems this test could be broken easily by changes in the client's implementation details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do, I mostly copied this pattern from existing tests so I'm not sure if you'd prefer consistency with those tests over stability for this test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer stability here. Your stable test can act as a good example of how to correctly write tests and that pattern can then be used for future tests. I think changing the other tests to follow your pattern of stable tests can also be a good first issue for new contributors.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cprussin @rajatkumar I refactored the test so that it doesn't rely on any arbitrary timeout, but instead relies on the actual state of the request/response lifecycle. Let me know if that looks good to you!

});

FAST_CLIENT.get('/foobar', function(err, _, res) {
t.ok(err);
t.equal(err.name, 'RequestTimeoutError');
});
});

test('should increment/decrement inflight request count', function(t) {
SERVER.get('/foo', function(req, res, next) {
t.equal(SERVER.inflightRequests(), 1);
Expand Down