'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;