-
Notifications
You must be signed in to change notification settings - Fork 982
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
Create inflightRequestThrottle plugin #1431
Conversation
docs/api/plugins.md
Outdated
@@ -153,6 +153,13 @@ event, e.g., `server.on('after', plugins.metrics());`: | |||
* `res` {Object} the response obj | |||
* `route` {Object} the route obj that serviced the request | |||
|
|||
The module includes the following plugins to be used with restify's `pre` event: | |||
* `inflightRequestThrottle(options)` - limits the max number of inflight requests | |||
* `options.limit` {Number} the maximum number of simultaneous connections the server will handle before returning an error |
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.
options
vs opts
?
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.
Second this -- let's keep it consistent :)
docs/api/plugins.md
Outdated
```js | ||
const opts = { limit: 600, server: server }; | ||
opts.error = new Error('Resource Exhausted'); | ||
error.statuscode = 420; |
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.
Should that be camelCase statusCode
? Also, I might suggest adding an example using restify-errors constructors.
docs/api/plugins.md
Outdated
|
||
```js | ||
const opts = { limit: 600, server: server }; | ||
opts.error = new Error('Resource Exhausted'); |
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.
Is it opts.error
or opts.resp
?
plugin: 'inflightRequestThrottle', | ||
inflightRequests: inflightRequests, | ||
limit: self._limit, | ||
message: 'maximum inflight requests exceeded, rejecting request' |
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.
Whoops, sorry, I should have been clearer about my last comment on this. I meant using the logger API itself, so something like this:
req.log.trace({
plugin: 'inflightRequestThrottle',
inflightRequests: inflightRequests,
limit: self._limit
}, 'maximum inflight requests exceeded, rejecting request');
@DonutEspresso one more time? |
docs/api/plugins.md
Outdated
@@ -153,6 +153,13 @@ event, e.g., `server.on('after', plugins.metrics());`: | |||
* `res` {Object} the response obj | |||
* `route` {Object} the route obj that serviced the request | |||
|
|||
The module includes the following plugins to be used with restify's `pre` event: | |||
* `inflightRequestThrottle(options)` - limits the max number of inflight requests | |||
* `options.limit` {Number} the maximum number of simultaneous connections the server will handle before returning an error |
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/simultaneous connections/inflight requests.
docs/api/plugins.md
Outdated
The module includes the following plugins to be used with restify's `pre` event: | ||
* `inflightRequestThrottle(options)` - limits the max number of inflight requests | ||
* `options.limit` {Number} the maximum number of simultaneous connections the server will handle before returning an error | ||
* `options.resp` {Error} An error that will be passed to `res.send` when the limit is reached. |
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.
what does resp
stand for? Response? If so can use the convention of res
?
docs/api/plugins.md
Outdated
## Inflight Request Throttling | ||
|
||
```js | ||
const options = { limit: 600, server: server }; |
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 server
property is not in docs. Do we need to pass in server
or should we be only passing in the specific properties that the throttle plugin needs?
docs/api/plugins.md
Outdated
|
||
```js | ||
const options = { limit: 600, server: server }; | ||
options.resp = new require('restify-errors').InternalServerError(); |
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.
Since people copy paste snippets all the time, we should hoist the require up to the top and then call new
on the constructor. Additionally, I thought this was a response? Why is it now an error object?
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.
Errors get serialized by res.__send
lib/plugins/index.js
Outdated
@@ -25,6 +25,7 @@ module.exports = { | |||
serveStatic: require('./static'), | |||
throttle: require('./throttle'), | |||
urlEncodedBodyParser: require('./formBodyParser'), | |||
inflightRequestThrottle: require('./inflightRequestThrottle'), |
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 generally sort these alphabetically -- so please do that. And yes it'd be awesome if we had a lint rule for this, but we don't yet :(
* server. | ||
* @returns {Function} middleware to be registered on server.pre | ||
*/ | ||
function inflightRequestThrottle (opts) { |
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.
Does this class need a constructor? Generally, the pattern for plugins in restify has been to use a closure, and obviating the need for a constructor. Can we keep it consistent and do that here? We can of course, debate closure vs constructor trade offs at another point in time. Here's an example: https://github.com/restify/node-restify/blob/5.x/lib/plugins/metrics.js#L23
@yunong one more time? |
docs/api/plugins.md
Outdated
The module includes the following plugins to be used with restify's `pre` event: | ||
* `inflightRequestThrottle(options)` - limits the max number of inflight requests | ||
* `options.limit` {Number} the maximum number of inflight requests the server will handle before returning an error | ||
* `options.res` {Error} An error that will be passed to `res.send` when the limit is reached. |
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.
Sorry to go one more time on this -- now that I understand this is an actual error, can we just name it options.err instead? That makes it a lot more clear, at least to me. Thoughts? And totally my bad for not realizing this in the first place.
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.
Agreed, options.res
doesn't feel intuitive.
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.
Yup, I totally agree. This grew organically since the original implementation expected this to be an array of parameters that would be passed to res.send.apply
. Now that we expect a restify error, its an awkward fit.
var assert = require('chai').assert; | ||
var restify = require('../../lib/index.js'); | ||
var restifyClients = require('restify-clients'); | ||
var P = restify.plugins.inflightRequestThrottle; |
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 P?
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.
Line length in the tests, it stands for Plugin
. I will try something else though, single letter variables feel wrong.
docs/api/plugins.md
Outdated
* `inflightRequestThrottle(options)` - limits the max number of inflight requests | ||
* `options.limit` {Number} the maximum number of inflight requests the server will handle before returning an error | ||
* `options.res` {Error} An error that will be passed to `res.send` when the limit is reached. | ||
* `options.res.statusCode` {Number} The status code to return when the limit is reached. |
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 terms of StatusCode here -- I almost think we should have the user just pass in a restify error of their choosing, and eliminate having to side channel the status code here. If they want to override the status code, they can just pass in an error they construct which contains the statuscode.
var defaultResponse = new ServiceUnavailableError('resource exhausted'); | ||
|
||
/** | ||
* inflightRequestThrottle |
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.
You may want to specify both here and in docs that users should register this plugin first as order matters and you want the throttle check to occur as early as possible.
@yunong one more time? |
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.
Looks good, nice work 👍
❤️ |
Plugin for limiting inflight requests