2021-12-03 17:58:48 +01:00

77 lines
2.8 KiB
JavaScript

'use strict';
var assert = require('assert-plus');
var ServiceUnavailableError = require('restify-errors').ServiceUnavailableError;
/**
* The `inflightRequestThrottle` module allows you to specify an upper limit to
* the maximum number of inflight requests your server is able to handle. This
* is a simple heuristic for protecting against event loop contention between
* requests causing unacceptable latencies.
*
* The custom error is optional, and allows you to specify your own response
* and status code when rejecting incoming requests due to too many inflight
* requests. It defaults to `503 ServiceUnavailableError`.
*
* This plugin should be registered as early as possibly in the middleware stack
* using `pre` to avoid performing unnecessary work.
*
* @public
* @function inflightRequestThrottle
* @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
* @example
* var errors = require('restify-errors');
* var restify = require('restify');
*
* var server = restify.createServer();
* const options = { limit: 600, server: server };
* options.res = new errors.InternalServerError();
* server.pre(restify.plugins.inflightRequestThrottle(options));
*/
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.err must be an error');
assert.optionalNumber(opts.err.statusCode, 'opts.err.statusCode');
}
var plugin = {};
plugin._err = opts.err || new ServiceUnavailableError('resource exhausted');
plugin._limit = opts.limit;
plugin._server = opts.server;
function onRequest(req, res, next) {
var inflightRequests = plugin._server.inflightRequests();
if (inflightRequests > plugin._limit) {
req.log.trace(
{
plugin: 'inflightRequestThrottle',
inflightRequests: inflightRequests,
limit: plugin._limit
},
'maximum inflight requests exceeded, rejecting request'
);
return next(plugin._err);
}
return next();
}
return onRequest;
}
module.exports = inflightRequestThrottle;