From: Bill Erickson Date: Fri, 22 Jan 2021 20:53:40 +0000 (-0500) Subject: LP1912834 OpenSRF JS Max Parallel Requests X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=780ed668406b1f4fc181100e47374b46238fe3f7;p=working%2FOpenSRF.git 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 --- diff --git a/src/javascript/opensrf.js b/src/javascript/opensrf.js index 03c79a9..fab7486 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,60 @@ OpenSRF.set_subclass = function(cls, pcls) { }; +// Some static request queueing functions. +OpenSRF.pendingRequests = []; +OpenSRF.activeRequests = []; +OpenSRF.throttleAlerted = false; + +OpenSRF.sendFromQueue = function() { + var pending = OpenSRF.pendingRequests; + var active = OpenSRF.activeRequests; + + while (pending.length > 0 && active.length < MAX_PARALLEL_REQUESTS) { + var request = pending.shift(); + active.push(request); + + var ses = request.session; + var osrf_msg = request.osrf_msg; + var req_args = request.req_args; + + 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; + } +} + +OpenSRF.removeFromQueue = function(session, osrf_msg) { + var sesThread = session.thread; + var msgThread = osrf_msg.threadTrace(); + + // Start at the front of the list as those requests are + // more likely to be complete just by FIFO logic. + for (var idx = OpenSRF.activeRequests.length - 1; idx > 0; idx--) { + var req = OpenSRF.activeRequests[idx]; + if (req.session.thread == sesThread && + req.osrf_msg.threadTrace() == msgThread) { + OpenSRF.activeRequests.splice(idx, 1); + } + } + + // 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 +345,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 +771,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) { @@ -727,6 +793,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); }