From 6604bb506bcd3b3ff9d03866bdd10df1fbe3da09 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Fri, 22 Jan 2021 15:53:40 -0500 Subject: [PATCH] LP1912834 OpenSRF JS Max Parallel Requests Limit the number of active network requests coming from OpenSRF (WebSocket, XHR) to avoid flooding servers with excessive numbers of active requests. The value is currently hardcoded to 5 in opensrf.js. When the max number of requests limit is reached and new requests continue to arrive, a warning message is logged to notify the developer to consider refactoring the client code to use batched calls / API's. Signed-off-by: Bill Erickson --- src/javascript/opensrf.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/javascript/opensrf.js b/src/javascript/opensrf.js index 03c79a9..4e138f5 100644 --- a/src/javascript/opensrf.js +++ b/src/javascript/opensrf.js @@ -64,6 +64,8 @@ var OSRF_STATUS_VERSIONNOTSUPPORTED = 505; // TODO: get path from ./configure prefix var SHARED_WORKER_LIB = '/js/dojo/opensrf/opensrf_ws_shared.js'; +var MAX_PARALLEL_REQUESTS = 5; + /* The following classes map directly to network-serializable opensrf objects */ function osrfMessage(hash) { @@ -272,6 +274,57 @@ OpenSRF.set_subclass = function(cls, pcls) { }; +// Some static request queueing functions. +OpenSRF.pendingRequests = []; +OpenSRF.throttleAlerted = false; +OpenSRF.activeCount = 0; + +OpenSRF.sendFromQueue = function() { + var pending = OpenSRF.pendingRequests; + + while (pending.length > 0 && OpenSRF.activeCount < MAX_PARALLEL_REQUESTS) { + var request = pending.shift(); + + var ses = request.session; + var osrf_msg = request.osrf_msg; + var req_args = request.req_args; + + if (osrf_msg.type() != 'DISCONNECT') { + // DISCONNECT messages do not return a response, so there's + // no way to know when have completed. Avoid tracking them + // as 'active' + OpenSRF.activeCount++; + } + + ses.sendToNet(osrf_msg, req_args); + } + + if (pending.length > 0) { + if (!OpenSRF.throttleAlerted) { + + OpenSRF.throttleAlerted = true; + // Seeing this log in the console means the coder + // should consider refactoring to use batch calls. + console.warn('Net throttling activated on max requests'); + } + + } else { + // Reset now the backlog has been cleared. + OpenSRF.throttleAlerted = false; + } + + // Useful for debugging issues with pending/active queues + //console.log('pending: ' + pending.length + ' active: ' + OpenSRF.activeCount); +} + +OpenSRF.removeFromQueue = function() { + OpenSRF.activeCount--; + + // Every completed request is a chance for a pending request + // to make it to the big leagues. + OpenSRF.sendFromQueue(); +} + /* general session superclass */ OpenSRF.Session = function() { this.remote_id = null; @@ -289,6 +342,15 @@ OpenSRF.Session.prototype.cleanup = function() { }; OpenSRF.Session.prototype.send = function(osrf_msg, args) { + OpenSRF.pendingRequests.push({ + session: this, + osrf_msg: osrf_msg, + req_args: args + }); + OpenSRF.sendFromQueue(); +} + +OpenSRF.Session.prototype.sendToNet = function(osrf_msg, args) { args = (args) ? args : {}; switch(OpenSRF.Session.transport) { case OSRF_TRANSPORT_TYPE_WS: @@ -706,6 +768,7 @@ OpenSRF.Stack.handle_message = function(ses, osrf_msg) { if(status == OSRF_STATUS_COMPLETE) { + OpenSRF.removeFromQueue(ses, osrf_msg); if(req) { req.complete = true; if(req.oncomplete && !req.oncomplete_called) { @@ -716,6 +779,7 @@ OpenSRF.Stack.handle_message = function(ses, osrf_msg) { } if(status == OSRF_STATUS_OK) { + OpenSRF.removeFromQueue(ses, osrf_msg); ses.state = OSRF_APP_SESSION_CONNECTED; /* call the connect callback */ @@ -727,6 +791,7 @@ OpenSRF.Stack.handle_message = function(ses, osrf_msg) { // capture all 400's and 500's as method errors if ((status+'').match(/^4/) || (status+'').match(/^5/)) { + OpenSRF.removeFromQueue(ses, osrf_msg); if(req && req.onmethoderror) return req.onmethoderror(req, status, status_text); } -- 2.11.0