@resolveio/server-lib 20.7.72 → 20.7.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.WorkerDispatcherManager=void 0;var common_1=require("../util/common"),WorkerDispatcherManager=function(){function WorkerDispatcherManager(){this._workers=[],this._taskQueue=[],this._clientRequests={},this._pendingTasks=new Map,this.MAX_CONCURRENCY=10}return WorkerDispatcherManager.create=function(e,t){var r=new WorkerDispatcherManager;return r.initialize(e,t),r},WorkerDispatcherManager.prototype.initialize=function(e,t){var r=this;this._websocketManager=e,this._methodManager=t,setInterval(function(){console.log(new Date,JSON.stringify(r._workers.map(function(e){return e.activeTasks}),null,2))},5e3)},WorkerDispatcherManager.prototype.isSafeShutdown=function(){return!this._taskQueue.length&&!this._pendingTasks.size},WorkerDispatcherManager.prototype.addWorker=function(e){this._workers.push({id:e.id_worker,ws:e,activeTasks:[]}),this._taskQueue.length&&this.dispatchQueue()},WorkerDispatcherManager.prototype.disconnectWorker=function(t){this._workers=this._workers.filter(function(e){return e.id!==t})},WorkerDispatcherManager.prototype.sendClientTask=function(e,t,r,s){var a="task-"+(0,common_1.objectIdHexString)();this._taskQueue.push({type:"task",taskId:a,messageId:e,method:t,params:r,userContext:s}),s&&s.id_ws&&(this._clientRequests[a]=s.id_ws),this.dispatchQueue()},WorkerDispatcherManager.prototype.sendInternalTask=function(e,t){void 0===t&&(t=[]),Array.isArray(t)||(t=[t]);var r="task-"+(0,common_1.objectIdHexString)();this._taskQueue.push({type:"task",taskId:r,method:e,params:t,messageId:0,userContext:{user:"Internal System"}}),this.dispatchQueue()},WorkerDispatcherManager.prototype.dispatchQueue=function(){var e=this;if(this._taskQueue.length)for(;0<this._taskQueue.length;){var t=this.findAvailableWorker();if(!t)return void setTimeout(function(){e.dispatchQueue()},25);var r=this._taskQueue.shift();this.assignTaskToWorker(t,r)}},WorkerDispatcherManager.prototype.findAvailableWorker=function(){var t=this,e=this._workers.filter(function(e){return e.activeTasks.length<t.MAX_CONCURRENCY});return e.length?(e.sort(function(e,t){return e.activeTasks.map(function(e){return e.weight}).reduce(function(e,t){return e+t},0)-t.activeTasks.map(function(e){return e.weight}).reduce(function(e,t){return e+t},0)}),e[0]):null},WorkerDispatcherManager.prototype.assignTaskToWorker=function(r,s){var a=this,e=this._methodManager.getMethod(s.method);if(e){r.activeTasks.push({taskId:s.taskId,weight:e&&e.workerTaskWeight?e.workerTaskWeight:1});var e={type:"task",taskId:s.taskId,messageId:s.messageId,method:s.method,params:s.params,userContext:s.userContext||{}},t=setTimeout(function(){var e,t;a._pendingTasks.has(s.taskId)&&a._pendingTasks.delete(s.taskId),console.log(new Date,"TIMEOUT HIT","task",s.taskId,s.messageId,s.method,JSON.stringify(a._workers.map(function(e){return e.activeTasks}))),r.activeTasks=r.activeTasks.filter(function(e){return e.taskId!==s.taskId}),s.userContext&&s.userContext.id_ws&&(e={messageId:s.messageId,hasError:!0,data:"Task timed out after 2m in WorkerDispatcherManager for method: "+s.method},t=a._websocketManager.getWebSocket(s.userContext.id_ws))&&a._websocketManager.send(t,e)},12e4);this._pendingTasks.set(s.taskId,{timeout:t});try{this.sendWorkerPayload(r.ws,e)}catch(e){console.error("Failed to send task to worker:",e),clearTimeout(t),r.activeTasks=r.activeTasks.filter(function(e){return e.taskId!==s.taskId}),this._taskQueue.unshift(s),this.dispatchQueue()}}else console.error("Failed to send task to worker - Could not find method:",s.method)},WorkerDispatcherManager.prototype.handleWorkerMessage=function(t,r){var s,e,a,i;try{e=JSON.parse(r,common_1.dateReviver)}catch(e){return void console.error("Failed to parse worker message:",r)}"taskComplete"===e.type&&((r=this._workers.find(function(e){return e.id===t}))?(s=e.taskId,a=e.messageId,i=e.error,e=e.result,r.activeTasks=r.activeTasks.filter(function(e){return e.taskId!==s}),(r=this._pendingTasks.get(s))&&(clearTimeout(r.timeout),this._pendingTasks.delete(s)),(r=this._clientRequests[s])&&(a={messageId:a,hasError:!1,data:e},i&&(a.hasError=!0,a.data=e),(i=this._websocketManager.getWebSocket(r))&&this._websocketManager.send(i,a),this._clientRequests[s])&&delete this._clientRequests[s],this._taskQueue.length&&this.dispatchQueue()):console.error("Unknown worker for taskComplete:",t))},WorkerDispatcherManager.prototype.sendWorkerPayload=function(e,t){if("string"!=typeof t&&(t=JSON.stringify(t)),e&&e.readyState===e.OPEN)try{e.send(t)}catch(e){console.error("Failed to send worker response:",e)}else e&&e.close()},WorkerDispatcherManager}();exports.WorkerDispatcherManager=WorkerDispatcherManager;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.WorkerDispatcherManager=void 0;var common_1=require("../util/common"),WorkerDispatcherManager=function(){function WorkerDispatcherManager(){this._workers=[],this._taskQueue=[],this._clientRequests={},this._pendingTasks=new Map,this.MAX_CONCURRENCY=10}return WorkerDispatcherManager.create=function(e,t){var r=new WorkerDispatcherManager;return r.initialize(e,t),r},WorkerDispatcherManager.prototype.initialize=function(e,t){this._websocketManager=e,this._methodManager=t},WorkerDispatcherManager.prototype.isSafeShutdown=function(){return!this._taskQueue.length&&!this._pendingTasks.size},WorkerDispatcherManager.prototype.addWorker=function(e){this._workers.push({id:e.id_worker,ws:e,activeTasks:[]}),this._taskQueue.length&&this.dispatchQueue()},WorkerDispatcherManager.prototype.disconnectWorker=function(t){this._workers=this._workers.filter(function(e){return e.id!==t})},WorkerDispatcherManager.prototype.sendClientTask=function(e,t,r,s){var a="task-"+(0,common_1.objectIdHexString)();this._taskQueue.push({type:"task",taskId:a,messageId:e,method:t,params:r,userContext:s}),s&&s.id_ws&&(this._clientRequests[a]=s.id_ws),this.dispatchQueue()},WorkerDispatcherManager.prototype.sendInternalTask=function(e,t){void 0===t&&(t=[]),Array.isArray(t)||(t=[t]);var r="task-"+(0,common_1.objectIdHexString)();this._taskQueue.push({type:"task",taskId:r,method:e,params:t,messageId:0,userContext:{user:"Internal System"}}),this.dispatchQueue()},WorkerDispatcherManager.prototype.dispatchQueue=function(){var e=this;if(this._taskQueue.length)for(;0<this._taskQueue.length;){var t=this.findAvailableWorker();if(!t)return void setTimeout(function(){e.dispatchQueue()},25);var r=this._taskQueue.shift();this.assignTaskToWorker(t,r)}},WorkerDispatcherManager.prototype.findAvailableWorker=function(){var t=this,e=this._workers.filter(function(e){return e.activeTasks.length<t.MAX_CONCURRENCY});return e.length?(e.sort(function(e,t){return e.activeTasks.map(function(e){return e.weight}).reduce(function(e,t){return e+t},0)-t.activeTasks.map(function(e){return e.weight}).reduce(function(e,t){return e+t},0)}),e[0]):null},WorkerDispatcherManager.prototype.assignTaskToWorker=function(r,s){var a=this,e=this._methodManager.getMethod(s.method);if(e){r.activeTasks.push({taskId:s.taskId,weight:e&&e.workerTaskWeight?e.workerTaskWeight:1});var e={type:"task",taskId:s.taskId,messageId:s.messageId,method:s.method,params:s.params,userContext:s.userContext||{}},t=setTimeout(function(){var e,t;a._pendingTasks.has(s.taskId)&&a._pendingTasks.delete(s.taskId),console.log(new Date,"TIMEOUT HIT","task",s.taskId,s.messageId,s.method,JSON.stringify(a._workers.map(function(e){return e.activeTasks}))),r.activeTasks=r.activeTasks.filter(function(e){return e.taskId!==s.taskId}),s.userContext&&s.userContext.id_ws&&(e={messageId:s.messageId,hasError:!0,data:"Task timed out after 2m in WorkerDispatcherManager for method: "+s.method},t=a._websocketManager.getWebSocket(s.userContext.id_ws))&&a._websocketManager.send(t,e)},12e4);this._pendingTasks.set(s.taskId,{timeout:t});try{this.sendWorkerPayload(r.ws,e)}catch(e){console.error("Failed to send task to worker:",e),clearTimeout(t),r.activeTasks=r.activeTasks.filter(function(e){return e.taskId!==s.taskId}),this._taskQueue.unshift(s),this.dispatchQueue()}}else console.error("Failed to send task to worker - Could not find method:",s.method)},WorkerDispatcherManager.prototype.handleWorkerMessage=function(t,r){var s,e,a,i;try{e=JSON.parse(r,common_1.dateReviver)}catch(e){return void console.error("Failed to parse worker message:",r)}"taskComplete"===e.type&&((r=this._workers.find(function(e){return e.id===t}))?(s=e.taskId,a=e.messageId,i=e.error,e=e.result,r.activeTasks=r.activeTasks.filter(function(e){return e.taskId!==s}),(r=this._pendingTasks.get(s))&&(clearTimeout(r.timeout),this._pendingTasks.delete(s)),(r=this._clientRequests[s])&&(a={messageId:a,hasError:!1,data:e},i&&(a.hasError=!0,a.data=e),(i=this._websocketManager.getWebSocket(r))&&this._websocketManager.send(i,a),this._clientRequests[s])&&delete this._clientRequests[s],this._taskQueue.length&&this.dispatchQueue()):console.error("Unknown worker for taskComplete:",t))},WorkerDispatcherManager.prototype.sendWorkerPayload=function(t,r){if("string"!=typeof r&&(r=JSON.stringify(r)),t&&t.readyState===t.OPEN)try{t.send(r)}catch(e){var s=JSON.parse(r,common_1.dateReviver);this._taskQueue.unshift(s),this.dispatchQueue(),this.disconnectWorker(t.id_worker),t.close(),console.error("Failed to send worker response:",e)}else t&&(s=JSON.parse(r,common_1.dateReviver),this._taskQueue.unshift(s),this.dispatchQueue(),this.disconnectWorker(t.id_worker),t.close())},WorkerDispatcherManager}();exports.WorkerDispatcherManager=WorkerDispatcherManager;
2
2
  //# sourceMappingURL=worker-dispatcher.manager.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/managers/worker-dispatcher.manager.ts"],"names":["common_1","require","WorkerDispatcherManager","this","_workers","_taskQueue","_clientRequests","_pendingTasks","Map","MAX_CONCURRENCY","create","websocketManager","methodManager","workerDispatcherManager","initialize","prototype","_this","_websocketManager","_methodManager","setInterval","console","log","Date","JSON","stringify","map","a","activeTasks","isSafeShutdown","length","size","addWorker","ws","push","id","dispatchQueue","disconnectWorker","workerId","filter","w","sendClientTask","messageId","method","params","userContext","taskId","objectIdHexString","type","id_ws","sendInternalTask","Array","isArray","user","worker","findAvailableWorker","setTimeout","task","shift","assignTaskToWorker","candidates","x","sort","y","weight","reduce","b","getMethod","workerTaskWeight","payload","timeoutHandle","timeoutRes","clientWS","has","delete","hasError","data","getWebSocket","send","set","timeout","sendWorkerPayload","err","error","clearTimeout","unshift","handleWorkerMessage","messageStr","taskId_1","result","res","clientReqWS","parse","dateReviver","_a","find","pendingTask","get","clientReqId","readyState","OPEN","close","exports"],"mappings":"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","file":"worker-dispatcher.manager.js","sourcesContent":["import * as WebSocket from 'ws';\nimport { ServerResponseModel, TaskPayload, TaskResponse } from '../models/server-message.model';\nimport { dateReviver, objectIdHexString } from '../util/common';\nimport { MethodManager } from './method.manager';\nimport { WebSocketManager } from './websocket.manager';\n\nexport interface WorkerConnection {\n id: string;\n ws: WebSocket.WebSocket;\n activeTasks: { taskId: string, weight: number }[];\n}\n\nexport class WorkerDispatcherManager {\n\tprivate _websocketManager: WebSocketManager;\n\tprivate _methodManager: MethodManager;\n private _workers: WorkerConnection[] = [];\n\tprivate _taskQueue: TaskPayload[] = [];\n private _clientRequests: { [taskId: string]: string } = {};\n\tprivate _pendingTasks: Map<string, {\n\t\ttimeout: NodeJS.Timeout;\n\t}> = new Map();\n\n private MAX_CONCURRENCY = 10;\n\n constructor() {}\n \n static create(websocketManager: WebSocketManager, methodManager: MethodManager) {\n const workerDispatcherManager = new WorkerDispatcherManager();\n workerDispatcherManager.initialize(websocketManager, methodManager);\n return workerDispatcherManager;\n }\n\n public initialize(websocketManager: WebSocketManager, methodManager: MethodManager) {\n\t\tthis._websocketManager = websocketManager;\n\t\tthis._methodManager = methodManager;\n\n\t\tsetInterval(() => {\n\t\t\tconsole.log(new Date(), JSON.stringify(this._workers.map(a => a.activeTasks), null, 2));\n\t\t}, 5000);\n }\n\n\tpublic isSafeShutdown() {\n\t\treturn !this._taskQueue.length && !this._pendingTasks.size;\n\t}\n\n public addWorker(ws: WebSocket.WebSocket) {\n this._workers.push({\n\t\t\tid: ws['id_worker'],\n\t\t\tws: ws,\n\t\t\tactiveTasks: []\n\t\t});\n\n\t\tif (this._taskQueue.length) {\n\t\t\tthis.dispatchQueue();\n\t\t}\n }\n\n\tpublic disconnectWorker(workerId: string) {\n\t\tthis._workers = this._workers.filter(w => w.id !== workerId);\n\t}\n\n /**\n\t * Add a new task to our in-memory queue and try to dispatch.\n\t */\n\tpublic sendClientTask(messageId: number, method: string, params: any[], userContext?: { id_user?: string; user?: string; id_ws?: string }) {\n\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\tthis._taskQueue.push({\n\t\t\ttype: 'task',\n\t\t\ttaskId,\n\t\t\tmessageId,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t\tuserContext\n\t\t});\n\n\t\tif (userContext && userContext.id_ws) {\n\t\t\t// console.log(new Date(), 'Send Client Task', userContext, taskId);\n\t\t\tthis._clientRequests[taskId] = userContext.id_ws;\n\t\t}\n\n\t\tthis.dispatchQueue();\n\t}\n\n\tpublic sendInternalTask(method: string, params = []) {\n\t\tif (!Array.isArray(params)) {\n\t\t\tparams = [params];\n\t\t}\n\n\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\tthis._taskQueue.push({\n\t\t\ttype: 'task',\n\t\t\ttaskId,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t\tmessageId: 0,\n\t\t\tuserContext: {\n\t\t\t\tuser: 'Internal System'\n\t\t\t}\n\t\t});\n\n\t\tthis.dispatchQueue();\n\t}\n\n\t/**\n\t * The main loop that assigns tasks from _taskQueue to any worker that has capacity.\n\t */\n\tprivate dispatchQueue() {\n\t\tif (!this._taskQueue.length) {\n\t\t\treturn;\n\t\t}\n\n\t\twhile (this._taskQueue.length > 0) {\n\t\t\tlet worker = this.findAvailableWorker();\n\n\t\t\tif (!worker) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.dispatchQueue();\n\t\t\t\t}, 25);\n\t\t\t\t\n\t\t\t\treturn; // no worker can take more tasks\n\t\t\t}\n\n\t\t\t// Remove from queue\n\t\t\tlet task = this._taskQueue.shift();\n\t\t\tthis.assignTaskToWorker(worker, task);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the worker with the fewest activeTasks that is under maxConcurrency. Or null if none.\n\t */\n\tprivate findAvailableWorker(): WorkerConnection | null {\n\t\tlet candidates = this._workers.filter(x => x.activeTasks.length < this.MAX_CONCURRENCY);\n\t\tif (!candidates.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Sort by how busy they are\n\t\tcandidates.sort((x, y) => x.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0) - y.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0));\n\t\t// console.log('Best Candidate', JSON.stringify(candidates[0], null, 2));\n\t\treturn candidates[0];\n\t}\n\n\tprivate assignTaskToWorker(worker: WorkerConnection, task: TaskPayload) {\n\t\tlet method = this._methodManager.getMethod(task.method);\n\n\t\tif (!method) {\n\t\t\tconsole.error('Failed to send task to worker - Could not find method:', task.method);\n\t\t\treturn;\n\t\t}\n\n\t\tworker.activeTasks.push({\n\t\t\ttaskId: task.taskId,\n\t\t\tweight: method && method.workerTaskWeight ? method.workerTaskWeight : 1\n\t\t});\n\n\t\tlet payload: TaskPayload = {\n\t\t\ttype: 'task',\n\t\t\ttaskId: task.taskId,\n\t\t\tmessageId: task.messageId,\n\t\t\tmethod: task.method,\n\t\t\tparams: task.params,\n\t\t\tuserContext: task.userContext || {}\n\t\t};\n\n\t\tlet timeoutHandle = setTimeout(() => {\n\t\t\tif (this._pendingTasks.has(task.taskId)) {\n\t\t\t\tthis._pendingTasks.delete(task.taskId);\n\t\t\t}\n\n\t\t\tconsole.log(new Date(), 'TIMEOUT HIT', 'task', task.taskId, task.messageId, task.method, JSON.stringify(this._workers.map(a => a.activeTasks)));\n\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== task.taskId);\n\n\t\t\tif (task.userContext && task.userContext.id_ws) {\n\t\t\t\tlet timeoutRes: ServerResponseModel = {\n\t\t\t\t\tmessageId: task.messageId,\n\t\t\t\t\thasError: true,\n\t\t\t\t\tdata: 'Task timed out after 2m in WorkerDispatcherManager for method: ' + task.method\n\t\t\t\t};\n\n\t\t\t\tlet clientWS = this._websocketManager.getWebSocket(task.userContext.id_ws);\n\n\t\t\t\tif (clientWS) {\n\t\t\t\t\tthis._websocketManager.send(clientWS, timeoutRes);\n\t\t\t\t}\n\t\t\t}\n\t\t}, 120000);\n\n\t\tthis._pendingTasks.set(task.taskId, {\n\t\t\ttimeout: timeoutHandle\n\t\t});\n\n\t\t// console.log(new Date(), 'Sending Worker Msg', 'task', process.env.NODE_APP_INSTANCE, task.taskId, task.messageId, task.method, JSON.stringify(this._workers.map(a => a.activeTasks)));\n\n\t\ttry {\n\t\t\tthis.sendWorkerPayload(worker.ws, payload);\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to send task to worker:', err);\n\n\t\t\tclearTimeout(timeoutHandle);\n\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== task.taskId);\n\n\t\t\t// Put task back at front\n\t\t\tthis._taskQueue.unshift(task);\n\n\t\t\tthis.dispatchQueue();\n\t\t}\n\t}\n\n\t/**\n\t * Handle messages coming back from a worker (like 'taskComplete').\n\t */\n\tpublic handleWorkerMessage(workerId: string, messageStr: string) {\n\t\tlet data: TaskResponse;\n\t\t\n\t\ttry {\n\t\t\tdata = JSON.parse(messageStr, dateReviver);\n\t\t}\n\t\tcatch {\n\t\t\tconsole.error('Failed to parse worker message:', messageStr);\n\t\t\treturn;\n\t\t}\n\n\t\t// console.log('Recv Worker Msg', data.type, data.taskId, data.messageId, data.error);\n\n\t\tif (data.type === 'taskComplete') {\n\t\t\tlet worker = this._workers.find(x => x.id === workerId);\n\t\t\t\n\t\t\tif (!worker) {\n\t\t\t\tconsole.error('Unknown worker for taskComplete:', workerId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tlet { taskId, messageId, error, result } = data;\n\n\t\t\t// console.log(new Date(), 'Handle Worker Msg', 'taskComplete', process.env.NODE_APP_INSTANCE, taskId, JSON.stringify(this._workers.map(a => a.activeTasks)));\n\t\t\t\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== taskId);\n\n\t\t\tlet pendingTask = this._pendingTasks.get(taskId);\n\t\t\t\n\t\t\tif (pendingTask) {\n\t\t\t\tclearTimeout(pendingTask.timeout);\n\t\t\t\tthis._pendingTasks.delete(taskId);\n\t\t\t}\n\n\t\t\t// Look up original request\n\t\t\tlet clientReqId = this._clientRequests[taskId];\n\t\t\t\n\t\t\tif (clientReqId) {\n\t\t\t\t// Send the final response to the client\n\t\t\t\tlet res: ServerResponseModel = {\n\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: result\n\t\t\t\t};\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.hasError = true;\n\t\t\t\t\tres.data = result;\n\t\t\t\t}\n\n\t\t\t\tlet clientReqWS = this._websocketManager.getWebSocket(clientReqId);\n\n\t\t\t\tif (clientReqWS) {\n\t\t\t\t\tthis._websocketManager.send(clientReqWS, res);\n\t\t\t\t}\n\n\t\t\t\tif (this._clientRequests[taskId]) {\n\t\t\t\t\tdelete this._clientRequests[taskId];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Try to dispatch more from the queue\n\t\t\tif (this._taskQueue.length) {\n\t\t\t\tthis.dispatchQueue();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic sendWorkerPayload(ws: WebSocket.WebSocket, payload: TaskPayload | string) {\n if (typeof payload !== 'string') {\n payload = JSON.stringify(payload);\n }\n\n\t\t// console.log('Sending', payload);\n\n if (ws && ws.readyState === ws.OPEN) {\n try {\n ws.send(payload);\n }\n catch (err) {\n console.error('Failed to send worker response:', err);\n }\n }\n else if (ws) {\n ws.close();\n }\n }\n}"]}
1
+ {"version":3,"sources":["../../src/managers/worker-dispatcher.manager.ts"],"names":["common_1","require","WorkerDispatcherManager","this","_workers","_taskQueue","_clientRequests","_pendingTasks","Map","MAX_CONCURRENCY","create","websocketManager","methodManager","workerDispatcherManager","initialize","prototype","_websocketManager","_methodManager","isSafeShutdown","length","size","addWorker","ws","push","id","activeTasks","dispatchQueue","disconnectWorker","workerId","filter","w","sendClientTask","messageId","method","params","userContext","taskId","objectIdHexString","type","id_ws","sendInternalTask","Array","isArray","user","_this","worker","findAvailableWorker","setTimeout","task","shift","assignTaskToWorker","candidates","x","sort","y","map","a","weight","reduce","b","getMethod","workerTaskWeight","payload","timeoutHandle","timeoutRes","clientWS","has","delete","console","log","Date","JSON","stringify","hasError","data","getWebSocket","send","set","timeout","sendWorkerPayload","err","error","clearTimeout","unshift","handleWorkerMessage","messageStr","taskId_1","result","res","clientReqWS","parse","dateReviver","_a","find","pendingTask","get","clientReqId","readyState","OPEN","close","exports"],"mappings":"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","file":"worker-dispatcher.manager.js","sourcesContent":["import * as WebSocket from 'ws';\nimport { ServerResponseModel, TaskPayload, TaskResponse } from '../models/server-message.model';\nimport { dateReviver, objectIdHexString } from '../util/common';\nimport { MethodManager } from './method.manager';\nimport { WebSocketManager } from './websocket.manager';\n\nexport interface WorkerConnection {\n id: string;\n ws: WebSocket.WebSocket;\n activeTasks: { taskId: string, weight: number }[];\n}\n\nexport class WorkerDispatcherManager {\n\tprivate _websocketManager: WebSocketManager;\n\tprivate _methodManager: MethodManager;\n private _workers: WorkerConnection[] = [];\n\tprivate _taskQueue: TaskPayload[] = [];\n private _clientRequests: { [taskId: string]: string } = {};\n\tprivate _pendingTasks: Map<string, {\n\t\ttimeout: NodeJS.Timeout;\n\t}> = new Map();\n\n private MAX_CONCURRENCY = 10;\n\n constructor() {}\n \n static create(websocketManager: WebSocketManager, methodManager: MethodManager) {\n const workerDispatcherManager = new WorkerDispatcherManager();\n workerDispatcherManager.initialize(websocketManager, methodManager);\n return workerDispatcherManager;\n }\n\n public initialize(websocketManager: WebSocketManager, methodManager: MethodManager) {\n\t\tthis._websocketManager = websocketManager;\n\t\tthis._methodManager = methodManager;\n\n\t\t// setInterval(() => {\n\t\t// \tconsole.log(new Date(), JSON.stringify(this._workers.map(a => a.activeTasks), null, 2));\n\t\t// }, 5000);\n }\n\n\tpublic isSafeShutdown() {\n\t\treturn !this._taskQueue.length && !this._pendingTasks.size;\n\t}\n\n public addWorker(ws: WebSocket.WebSocket) {\n this._workers.push({\n\t\t\tid: ws['id_worker'],\n\t\t\tws: ws,\n\t\t\tactiveTasks: []\n\t\t});\n\n\t\tif (this._taskQueue.length) {\n\t\t\tthis.dispatchQueue();\n\t\t}\n }\n\n\tpublic disconnectWorker(workerId: string) {\n\t\tthis._workers = this._workers.filter(w => w.id !== workerId);\n\t}\n\n /**\n\t * Add a new task to our in-memory queue and try to dispatch.\n\t */\n\tpublic sendClientTask(messageId: number, method: string, params: any[], userContext?: { id_user?: string; user?: string; id_ws?: string }) {\n\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\tthis._taskQueue.push({\n\t\t\ttype: 'task',\n\t\t\ttaskId,\n\t\t\tmessageId,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t\tuserContext\n\t\t});\n\n\t\tif (userContext && userContext.id_ws) {\n\t\t\t// console.log(new Date(), 'Send Client Task', userContext, taskId);\n\t\t\tthis._clientRequests[taskId] = userContext.id_ws;\n\t\t}\n\n\t\tthis.dispatchQueue();\n\t}\n\n\tpublic sendInternalTask(method: string, params = []) {\n\t\tif (!Array.isArray(params)) {\n\t\t\tparams = [params];\n\t\t}\n\n\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\tthis._taskQueue.push({\n\t\t\ttype: 'task',\n\t\t\ttaskId,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t\tmessageId: 0,\n\t\t\tuserContext: {\n\t\t\t\tuser: 'Internal System'\n\t\t\t}\n\t\t});\n\n\t\tthis.dispatchQueue();\n\t}\n\n\t/**\n\t * The main loop that assigns tasks from _taskQueue to any worker that has capacity.\n\t */\n\tprivate dispatchQueue() {\n\t\tif (!this._taskQueue.length) {\n\t\t\treturn;\n\t\t}\n\n\t\twhile (this._taskQueue.length > 0) {\n\t\t\tlet worker = this.findAvailableWorker();\n\n\t\t\tif (!worker) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.dispatchQueue();\n\t\t\t\t}, 25);\n\t\t\t\t\n\t\t\t\treturn; // no worker can take more tasks\n\t\t\t}\n\n\t\t\t// Remove from queue\n\t\t\tlet task = this._taskQueue.shift();\n\t\t\tthis.assignTaskToWorker(worker, task);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the worker with the fewest activeTasks that is under maxConcurrency. Or null if none.\n\t */\n\tprivate findAvailableWorker(): WorkerConnection | null {\n\t\tlet candidates = this._workers.filter(x => x.activeTasks.length < this.MAX_CONCURRENCY);\n\t\tif (!candidates.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Sort by how busy they are\n\t\tcandidates.sort((x, y) => x.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0) - y.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0));\n\t\t// console.log('Best Candidate', JSON.stringify(candidates[0], null, 2));\n\t\treturn candidates[0];\n\t}\n\n\tprivate assignTaskToWorker(worker: WorkerConnection, task: TaskPayload) {\n\t\tlet method = this._methodManager.getMethod(task.method);\n\n\t\tif (!method) {\n\t\t\tconsole.error('Failed to send task to worker - Could not find method:', task.method);\n\t\t\treturn;\n\t\t}\n\n\t\tworker.activeTasks.push({\n\t\t\ttaskId: task.taskId,\n\t\t\tweight: method && method.workerTaskWeight ? method.workerTaskWeight : 1\n\t\t});\n\n\t\tlet payload: TaskPayload = {\n\t\t\ttype: 'task',\n\t\t\ttaskId: task.taskId,\n\t\t\tmessageId: task.messageId,\n\t\t\tmethod: task.method,\n\t\t\tparams: task.params,\n\t\t\tuserContext: task.userContext || {}\n\t\t};\n\n\t\tlet timeoutHandle = setTimeout(() => {\n\t\t\tif (this._pendingTasks.has(task.taskId)) {\n\t\t\t\tthis._pendingTasks.delete(task.taskId);\n\t\t\t}\n\n\t\t\tconsole.log(new Date(), 'TIMEOUT HIT', 'task', task.taskId, task.messageId, task.method, JSON.stringify(this._workers.map(a => a.activeTasks)));\n\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== task.taskId);\n\n\t\t\tif (task.userContext && task.userContext.id_ws) {\n\t\t\t\tlet timeoutRes: ServerResponseModel = {\n\t\t\t\t\tmessageId: task.messageId,\n\t\t\t\t\thasError: true,\n\t\t\t\t\tdata: 'Task timed out after 2m in WorkerDispatcherManager for method: ' + task.method\n\t\t\t\t};\n\n\t\t\t\tlet clientWS = this._websocketManager.getWebSocket(task.userContext.id_ws);\n\n\t\t\t\tif (clientWS) {\n\t\t\t\t\tthis._websocketManager.send(clientWS, timeoutRes);\n\t\t\t\t}\n\t\t\t}\n\t\t}, 120000);\n\n\t\tthis._pendingTasks.set(task.taskId, {\n\t\t\ttimeout: timeoutHandle\n\t\t});\n\n\t\t// console.log(new Date(), 'Sending Worker Msg', 'task', process.env.NODE_APP_INSTANCE, task.taskId, task.messageId, task.method, JSON.stringify(this._workers.map(a => a.activeTasks)));\n\n\t\ttry {\n\t\t\tthis.sendWorkerPayload(worker.ws, payload);\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to send task to worker:', err);\n\n\t\t\tclearTimeout(timeoutHandle);\n\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== task.taskId);\n\n\t\t\t// Put task back at front\n\t\t\tthis._taskQueue.unshift(task);\n\t\t\tthis.dispatchQueue();\n\t\t}\n\t}\n\n\t/**\n\t * Handle messages coming back from a worker (like 'taskComplete').\n\t */\n\tpublic handleWorkerMessage(workerId: string, messageStr: string) {\n\t\tlet data: TaskResponse;\n\t\t\n\t\ttry {\n\t\t\tdata = JSON.parse(messageStr, dateReviver);\n\t\t}\n\t\tcatch {\n\t\t\tconsole.error('Failed to parse worker message:', messageStr);\n\t\t\treturn;\n\t\t}\n\n\t\t// console.log('Recv Worker Msg', data.type, data.taskId, data.messageId, data.error);\n\n\t\tif (data.type === 'taskComplete') {\n\t\t\tlet worker = this._workers.find(x => x.id === workerId);\n\t\t\t\n\t\t\tif (!worker) {\n\t\t\t\tconsole.error('Unknown worker for taskComplete:', workerId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tlet { taskId, messageId, error, result } = data;\n\n\t\t\t// console.log(new Date(), 'Handle Worker Msg', 'taskComplete', process.env.NODE_APP_INSTANCE, taskId, JSON.stringify(this._workers.map(a => a.activeTasks)));\n\t\t\t\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== taskId);\n\n\t\t\tlet pendingTask = this._pendingTasks.get(taskId);\n\t\t\t\n\t\t\tif (pendingTask) {\n\t\t\t\tclearTimeout(pendingTask.timeout);\n\t\t\t\tthis._pendingTasks.delete(taskId);\n\t\t\t}\n\n\t\t\t// Look up original request\n\t\t\tlet clientReqId = this._clientRequests[taskId];\n\t\t\t\n\t\t\tif (clientReqId) {\n\t\t\t\t// Send the final response to the client\n\t\t\t\tlet res: ServerResponseModel = {\n\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: result\n\t\t\t\t};\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.hasError = true;\n\t\t\t\t\tres.data = result;\n\t\t\t\t}\n\n\t\t\t\tlet clientReqWS = this._websocketManager.getWebSocket(clientReqId);\n\n\t\t\t\tif (clientReqWS) {\n\t\t\t\t\tthis._websocketManager.send(clientReqWS, res);\n\t\t\t\t}\n\n\t\t\t\tif (this._clientRequests[taskId]) {\n\t\t\t\t\tdelete this._clientRequests[taskId];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Try to dispatch more from the queue\n\t\t\tif (this._taskQueue.length) {\n\t\t\t\tthis.dispatchQueue();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic sendWorkerPayload(ws: WebSocket.WebSocket, payload: TaskPayload | string) {\n if (typeof payload !== 'string') {\n payload = JSON.stringify(payload);\n }\n\n\t\t// console.log('Sending', payload);\n\n if (ws && ws.readyState === ws.OPEN) {\n try {\n ws.send(payload);\n }\n catch (err) {\n\t\t\t\tlet task = JSON.parse(payload, dateReviver);\n\t\t\t\t\n\t\t\t\t// Put task back at front\n\t\t\t\tthis._taskQueue.unshift(task);\n\t\t\t\tthis.dispatchQueue();\n\n\t\t\t\tthis.disconnectWorker(ws['id_worker']);\n\t\t\t\tws.close();\n console.error('Failed to send worker response:', err);\n }\n }\n else if (ws) {\n\t\t\t// Put task back at front\n\t\t\tlet task = JSON.parse(payload, dateReviver);\n\t\t\t\t\n\t\t\t// Put task back at front\n\t\t\tthis._taskQueue.unshift(task);\n\t\t\tthis.dispatchQueue();\n\n\t\t\tthis.disconnectWorker(ws['id_worker']);\n\t\t\tws.close();\n }\n }\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resolveio/server-lib",
3
- "version": "20.7.72",
3
+ "version": "20.7.74",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "package": "./build_package.sh",