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

Conversation

cprussin
Copy link
Contributor

@cprussin cprussin commented Mar 26, 2019

Pre-Submission Checklist

  • Opened an issue discussing these changes before opening the PR
  • Ran the linter and tests via make prepush
  • Included comprehensive and convincing tests for changes

Issues

Closes:

Summarize the issues that discussed these changes

The 'after' event is not called when a request has an uncaught exception (using handleUncaughtExceptions) if the request has been aborted before the exception.

Changes

What does this PR do?

This PR is a proposal for a mechanism to fix the issue by adding a continuation function to the uncaughtException handler. If this continuation function isn't called, then restify can never know that a request has completed all work and call the 'after' handler (because aborted is triggered on the request object before work has completed, so neither finish nor close ever get triggered on the response and thus we have no other signal that work has completed). This is actually consistent with how middlewares work--if next isn't called then the accounting will leak--so I believe the tradeoff is acceptable.

This pattern also allows for a fix without making a breaking API change.

@misterdjules misterdjules requested review from retrohacker and a team March 26, 2019 23:31
@misterdjules misterdjules changed the title Pass a next() to the uncaught exception handler feat: provide callback to uncaughtException handler Mar 26, 2019
@misterdjules
Copy link
Contributor

@cprussin I think this approach looks good to me. Two things I'd like to see as part of this PR and that are currently missing:

  1. New tests that make sure that inflight requests count is correctly tracked in the uncaught exception use case. Adding tests to https://github.com/restify/node-restify/blob/master/test/server.test.js#L2054 may be a good place to add those tests.
  2. Updating documentation in .md files to describe this new callback.

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.

// 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!

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!

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.

+1

@misterdjules
Copy link
Contributor

@cprussin @rajatkumar @hekike Updated this PR with a few more commits that I believe address all the comments in this PR. Please take another look!

@misterdjules misterdjules requested review from a team and DonutEspresso April 6, 2019 00:15
@hekike hekike self-requested a review April 8, 2019 17:17
@DonutEspresso DonutEspresso merged commit 5e8b5e2 into restify:master Apr 11, 2019
@cprussin cprussin deleted the cp_fix-inflight-request-counter-leak branch April 11, 2019 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants