Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import EventEmitter from 'events';
- import onFinished from 'on-finished';
- /*
- * RequestQueue to ensure that only a single request is executing at a time.
- *
- * This middleware intercepts requests as they come in by delaying executing of
- * next() until previous requests finish processing. This complements external
- * server configuration via haproxy or similar that restricts concurrent
- * requests. This per-process queue allows an application level guarantee of
- * mutual exclusion of requests. This allows that behavior to be depended
- * upon, allowing for safe (but careful) use of global state. Additionally,
- * this allows for lifecycle hooks to be added for the periods when no request
- * is currently executing, before or after the request has been run. These are
- * ideal points to install behavior to reset global state or perform actions
- * against the server at a "clean state" point in time.
- */
- export default class RequestQueue extends EventEmitter {
- constructor() {
- super();
- this.queue = [];
- this.current = null;
- this.outerMiddleware = this.outerMiddleware.bind(this);
- this.innerMiddleware = this.innerMiddleware.bind(this);
- this.finishCurrent = this.finishCurrent.bind(this);
- }
- process() {
- if (!this.current) {
- this.current = this.queue.shift();
- this.emit('queueLength', this.queue.length);
- if (this.current) {
- this.emit('beforeRequest');
- this.current.start();
- }
- } else {
- this.emit('queueLength', this.queue.length);
- }
- }
- /*
- * Outer middleware must be the very first middleware installed on the app.
- * This intercepts and begins queueing the request.
- */
- outerMiddleware(req, res, next) {
- const job = { req, res, start: next };
- this.push(job);
- }
- /*
- * Inner middleware must be last middleware installed before endpoints. This
- * is only necessary because on-finished executes its callbacks in the order
- * in which they were installed. We need this to be innermost so that we
- * advance the queue only after the request and all other on-finished
- * callbacks complete.
- *
- * Not adding this middleware will result in the queue never being drained.
- */
- innerMiddleware(req, res, next) {
- onFinished(res, this.finishCurrent);
- next();
- }
- push(job) {
- this.queue.push(job);
- this.process();
- }
- finishCurrent() {
- this.current = null;
- this.emit('afterRequest');
- this.process();
- }
- }
Add Comment
Please, Sign In to add comment