/
inflightRequestThrottle.js
64 lines (53 loc) · 2.27 KB
/
inflightRequestThrottle.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
'use strict';
var assert = require('assert-plus');
var ServiceUnavailableError = require('restify-errors').ServiceUnavailableError;
var defaultResponse = new ServiceUnavailableError('resource exhausted');
/**
* inflightRequestThrottle
*
* Place an upper limit on the number of inlfight requests restify will accept.
* For every request that exceeds this threshold, restify will respond with an
* error. This plugin should be registered as early as possible in the
* middleware stack using `pre` to avoid performing unnecessary work.
*
* @param {Object} opts configure this plugin
* @param {Number} opts.limit maximum number of inflight requests the server
* will handle before returning an error
* @param {Error} opts.err A restify error used as a response when the inflight
* request limit is exceeded
* @param {Function} opts.server the instance of the restify server this plugin
* will throttle.
* @returns {Function} middleware to be registered on server.pre
*/
function inflightRequestThrottle (opts) {
// Scrub input and populate our configuration
assert.object(opts, 'opts');
assert.number(opts.limit, 'opts.limit');
assert.object(opts.server, 'opts.server');
assert.func(opts.server.inflightRequests, 'opts.server.inflightRequests');
if (opts.err !== undefined && opts.err !== null) {
assert.ok(opts.err instanceof Error, 'opts.res must be an error');
assert.optionalNumber(opts.err.statusCode, 'opts.err.statusCode');
}
var self = {};
self._err = opts.err || defaultResponse;
self._limit = opts.limit;
self._server = opts.server;
function onRequest (req, res, next) {
var inflightRequests = self._server.inflightRequests();
if (inflightRequests > self._limit) {
req.log.trace({
plugin: 'inflightRequestThrottle',
inflightRequests: inflightRequests,
limit: self._limit
}, 'maximum inflight requests exceeded, rejecting request');
return res.send(self._err);
}
return next();
}
// We need to bind in order to keep our `this` context when passed back
// out of the constructor.
return onRequest;
}
inflightRequestThrottle.prototype.onRequest =
module.exports = inflightRequestThrottle;