@resolveio/server-lib 20.7.119 → 20.7.121
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.
- package/client-server-app.js +51 -1
- package/client-server-app.js.map +1 -1
- package/collections/app-status.collection.js +51 -1
- package/collections/app-status.collection.js.map +1 -1
- package/collections/counter.collection.js +55 -1
- package/collections/counter.collection.js.map +1 -1
- package/collections/cron-job-history.collection.js +136 -1
- package/collections/cron-job-history.collection.js.map +1 -1
- package/collections/cron-job.collection.js +87 -1
- package/collections/cron-job.collection.js.map +1 -1
- package/collections/email-history.collection.js +98 -1
- package/collections/email-history.collection.js.map +1 -1
- package/collections/email-verified.collection.js +60 -1
- package/collections/email-verified.collection.js.map +1 -1
- package/collections/file.collection.js +73 -1
- package/collections/file.collection.js.map +1 -1
- package/collections/flag-update.collection.js +56 -1
- package/collections/flag-update.collection.js.map +1 -1
- package/collections/flag.collection.js +56 -1
- package/collections/flag.collection.js.map +1 -1
- package/collections/log-method-latency.collection.js +72 -1
- package/collections/log-method-latency.collection.js.map +1 -1
- package/collections/log-subscription.collection.js +75 -1
- package/collections/log-subscription.collection.js.map +1 -1
- package/collections/log.collection.js +87 -1
- package/collections/log.collection.js.map +1 -1
- package/collections/logged-in-users.collection.js +66 -1
- package/collections/logged-in-users.collection.js.map +1 -1
- package/collections/monitor-cpu.collection.js +64 -1
- package/collections/monitor-cpu.collection.js.map +1 -1
- package/collections/monitor-function.collection.js +73 -1
- package/collections/monitor-function.collection.js.map +1 -1
- package/collections/monitor-memory.collection.js +76 -1
- package/collections/monitor-memory.collection.js.map +1 -1
- package/collections/monitor-mongo.collection.js +70 -1
- package/collections/monitor-mongo.collection.js.map +1 -1
- package/collections/notification.collection.js +56 -1
- package/collections/notification.collection.js.map +1 -1
- package/collections/report-builder-dashboard-builder.collection.js +108 -1
- package/collections/report-builder-dashboard-builder.collection.js.map +1 -1
- package/collections/report-builder-library.collection.js +86 -1
- package/collections/report-builder-library.collection.js.map +1 -1
- package/collections/report-builder-report.collection.js +148 -1
- package/collections/report-builder-report.collection.js.map +1 -1
- package/collections/user-group.collection.js +88 -1
- package/collections/user-group.collection.js.map +1 -1
- package/collections/user-guide.collection.js +56 -1
- package/collections/user-guide.collection.js.map +1 -1
- package/collections/user.collection.js +265 -1
- package/collections/user.collection.js.map +1 -1
- package/cron/cron.js +97 -1
- package/cron/cron.js.map +1 -1
- package/fixtures/cron-jobs.js +95 -1
- package/fixtures/cron-jobs.js.map +1 -1
- package/fixtures/init.js +78 -1
- package/fixtures/init.js.map +1 -1
- package/http/auth.js +869 -1
- package/http/auth.js.map +1 -1
- package/http/health.js +11 -1
- package/http/health.js.map +1 -1
- package/http/home.js +114 -1
- package/http/home.js.map +1 -1
- package/index.js +18 -1
- package/index.js.map +1 -1
- package/managers/cron.manager.js +461 -1
- package/managers/cron.manager.js.map +1 -1
- package/managers/local-log.manager.js +79 -1
- package/managers/local-log.manager.js.map +1 -1
- package/managers/method.manager.js +1023 -1
- package/managers/method.manager.js.map +1 -1
- package/managers/mongo.manager.js +4223 -1
- package/managers/mongo.manager.js.map +1 -1
- package/managers/monitor.manager.js +534 -1
- package/managers/monitor.manager.js.map +1 -1
- package/managers/subscription.manager.js +1292 -1
- package/managers/subscription.manager.js.map +1 -1
- package/managers/websocket.manager.js +165 -1
- package/managers/websocket.manager.js.map +1 -1
- package/managers/worker-dispatcher.manager.js +335 -1
- package/managers/worker-dispatcher.manager.js.map +1 -1
- package/managers/worker-server.manager.js +292 -1
- package/managers/worker-server.manager.js.map +1 -1
- package/methods/accounts.js +302 -1
- package/methods/accounts.js.map +1 -1
- package/methods/aws.js +748 -1
- package/methods/aws.js.map +1 -1
- package/methods/collections.js +542 -1
- package/methods/collections.js.map +1 -1
- package/methods/counters.js +111 -1
- package/methods/counters.js.map +1 -1
- package/methods/cron-jobs.js +1476 -1
- package/methods/cron-jobs.js.map +1 -1
- package/methods/flag-updates.js +8 -1
- package/methods/flag-updates.js.map +1 -1
- package/methods/flags.js +8 -1
- package/methods/flags.js.map +1 -1
- package/methods/logs.js +417 -1
- package/methods/logs.js.map +1 -1
- package/methods/monitor.js +543 -1
- package/methods/monitor.js.map +1 -1
- package/methods/pdf.js +742 -1
- package/methods/pdf.js.map +1 -1
- package/methods/report-builder.js +840 -1
- package/methods/report-builder.js.map +1 -1
- package/methods/support.js +232 -1
- package/methods/support.js.map +1 -1
- package/models/app-status.model.js +3 -1
- package/models/app-status.model.js.map +1 -1
- package/models/billing-logged-in-users.model.js +3 -1
- package/models/billing-logged-in-users.model.js.map +1 -1
- package/models/collection-document.model.js +3 -1
- package/models/collection-document.model.js.map +1 -1
- package/models/counter.model.js +3 -1
- package/models/counter.model.js.map +1 -1
- package/models/cron-job-history.model.js +3 -1
- package/models/cron-job-history.model.js.map +1 -1
- package/models/cron-job.model.js +3 -1
- package/models/cron-job.model.js.map +1 -1
- package/models/dialog.model.js +3 -1
- package/models/dialog.model.js.map +1 -1
- package/models/email-history.model.js +15 -1
- package/models/email-history.model.js.map +1 -1
- package/models/email-verified.model.js +3 -1
- package/models/email-verified.model.js.map +1 -1
- package/models/file.model.js +3 -1
- package/models/file.model.js.map +1 -1
- package/models/flag-update.model.js +3 -1
- package/models/flag-update.model.js.map +1 -1
- package/models/flag.model.js +3 -1
- package/models/flag.model.js.map +1 -1
- package/models/log-method-latency.model.js +3 -1
- package/models/log-method-latency.model.js.map +1 -1
- package/models/log-subscription.model.js +3 -1
- package/models/log-subscription.model.js.map +1 -1
- package/models/log.model.js +3 -1
- package/models/log.model.js.map +1 -1
- package/models/logged-in-users.model.js +3 -1
- package/models/logged-in-users.model.js.map +1 -1
- package/models/method-response.model.js +3 -1
- package/models/method-response.model.js.map +1 -1
- package/models/method.model.d.ts +0 -1
- package/models/method.model.js +3 -1
- package/models/method.model.js.map +1 -1
- package/models/monitor-cpu.model.js +3 -1
- package/models/monitor-cpu.model.js.map +1 -1
- package/models/monitor-function.model.js +3 -1
- package/models/monitor-function.model.js.map +1 -1
- package/models/monitor-memory.model.js +3 -1
- package/models/monitor-memory.model.js.map +1 -1
- package/models/monitor-mongo.model.js +3 -1
- package/models/monitor-mongo.model.js.map +1 -1
- package/models/notification.model.js +3 -1
- package/models/notification.model.js.map +1 -1
- package/models/pagination.model.js +23 -1
- package/models/pagination.model.js.map +1 -1
- package/models/permission.model.js +3 -1
- package/models/permission.model.js.map +1 -1
- package/models/report-builder-dashboard-builder.model.js +3 -1
- package/models/report-builder-dashboard-builder.model.js.map +1 -1
- package/models/report-builder-library.model.js +3 -1
- package/models/report-builder-library.model.js.map +1 -1
- package/models/report-builder-report.model.js +3 -1
- package/models/report-builder-report.model.js.map +1 -1
- package/models/report-builder.model.js +3 -1
- package/models/report-builder.model.js.map +1 -1
- package/models/select-data-label.model.js +3 -1
- package/models/select-data-label.model.js.map +1 -1
- package/models/server-message.model.js +3 -1
- package/models/server-message.model.js.map +1 -1
- package/models/subscription.model.js +3 -1
- package/models/subscription.model.js.map +1 -1
- package/models/support-ticket.model.js +3 -1
- package/models/support-ticket.model.js.map +1 -1
- package/models/user-group.model.js +3 -1
- package/models/user-group.model.js.map +1 -1
- package/models/user-guide.model.js +3 -1
- package/models/user-guide.model.js.map +1 -1
- package/models/user.model.js +3 -1
- package/models/user.model.js.map +1 -1
- package/package.json +1 -1
- package/public_api.js +77 -1
- package/public_api.js.map +1 -1
- package/publications/app-status.js +16 -1
- package/publications/app-status.js.map +1 -1
- package/publications/cron-jobs.js +32 -1
- package/publications/cron-jobs.js.map +1 -1
- package/publications/files.js +36 -1
- package/publications/files.js.map +1 -1
- package/publications/flags-update.js +22 -1
- package/publications/flags-update.js.map +1 -1
- package/publications/flags.js +22 -1
- package/publications/flags.js.map +1 -1
- package/publications/logs.js +164 -1
- package/publications/logs.js.map +1 -1
- package/publications/notifications.js +16 -1
- package/publications/notifications.js.map +1 -1
- package/publications/report-builder-dashboard-builders.js +42 -1
- package/publications/report-builder-dashboard-builders.js.map +1 -1
- package/publications/report-builder-libraries.js +90 -1
- package/publications/report-builder-libraries.js.map +1 -1
- package/publications/report-builder-reports.js +50 -1
- package/publications/report-builder-reports.js.map +1 -1
- package/publications/super-admin.js +16 -1
- package/publications/super-admin.js.map +1 -1
- package/publications/user-groups.js +16 -1
- package/publications/user-groups.js.map +1 -1
- package/publications/user-guides.js +16 -1
- package/publications/user-guides.js.map +1 -1
- package/resolveio-server-app.js +176 -1
- package/resolveio-server-app.js.map +1 -1
- package/server-app.js +1159 -1
- package/server-app.js.map +1 -1
- package/util/common.js +632 -1
- package/util/common.js.map +1 -1
- package/util/schema-report-builder.js +454 -1
- package/util/schema-report-builder.js.map +1 -1
|
@@ -1,2 +1,336 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkerDispatcherManager = void 0;
|
|
4
|
+
var common_1 = require("../util/common");
|
|
5
|
+
var WorkerDispatcherManager = /** @class */ (function () {
|
|
6
|
+
function WorkerDispatcherManager() {
|
|
7
|
+
this._workers = [];
|
|
8
|
+
this._taskQueue = [];
|
|
9
|
+
this._clientRequests = {};
|
|
10
|
+
this._pendingTasks = new Map();
|
|
11
|
+
this.MAX_CONCURRENCY = 10;
|
|
12
|
+
}
|
|
13
|
+
WorkerDispatcherManager.create = function (websocketManager, methodManager) {
|
|
14
|
+
var workerDispatcherManager = new WorkerDispatcherManager();
|
|
15
|
+
workerDispatcherManager.initialize(websocketManager, methodManager);
|
|
16
|
+
return workerDispatcherManager;
|
|
17
|
+
};
|
|
18
|
+
WorkerDispatcherManager.prototype.initialize = function (websocketManager, methodManager) {
|
|
19
|
+
this._websocketManager = websocketManager;
|
|
20
|
+
this._methodManager = methodManager;
|
|
21
|
+
};
|
|
22
|
+
WorkerDispatcherManager.prototype.isSafeShutdown = function () {
|
|
23
|
+
return !this._taskQueue.length && !this._pendingTasks.size;
|
|
24
|
+
};
|
|
25
|
+
WorkerDispatcherManager.prototype.addWorker = function (ws) {
|
|
26
|
+
var _this = this;
|
|
27
|
+
this._workers.push({
|
|
28
|
+
id: ws['id_worker'],
|
|
29
|
+
ws: ws,
|
|
30
|
+
activeTasks: []
|
|
31
|
+
});
|
|
32
|
+
setInterval(function () {
|
|
33
|
+
if (_this._methodManager.getEnableDebug()) {
|
|
34
|
+
console.log(JSON.stringify(_this._workers.map(function (a) {
|
|
35
|
+
return {
|
|
36
|
+
id: a.id,
|
|
37
|
+
activeTasks: a.activeTasks
|
|
38
|
+
};
|
|
39
|
+
}), null, 2));
|
|
40
|
+
}
|
|
41
|
+
}, 5000);
|
|
42
|
+
if (this._taskQueue.length) {
|
|
43
|
+
this.dispatchQueue();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
WorkerDispatcherManager.prototype.disconnectWorker = function (workerId) {
|
|
47
|
+
this._workers = this._workers.filter(function (w) { return w.id !== workerId; });
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Add a new task to our in-memory queue and try to dispatch.
|
|
51
|
+
*/
|
|
52
|
+
WorkerDispatcherManager.prototype.sendClientTask = function (messageId, method, params, userContext) {
|
|
53
|
+
var taskId = 'task-' + (0, common_1.objectIdHexString)();
|
|
54
|
+
this._taskQueue.push({
|
|
55
|
+
type: 'task',
|
|
56
|
+
taskId: taskId,
|
|
57
|
+
messageId: messageId,
|
|
58
|
+
method: method,
|
|
59
|
+
params: params,
|
|
60
|
+
userContext: userContext
|
|
61
|
+
});
|
|
62
|
+
if (userContext && userContext.id_ws) {
|
|
63
|
+
this._clientRequests[taskId] = userContext.id_ws;
|
|
64
|
+
}
|
|
65
|
+
this.dispatchQueue();
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Same as sendInternalTask but returns a Promise so you can `await` it.
|
|
69
|
+
*/
|
|
70
|
+
WorkerDispatcherManager.prototype.sendInternalPromise = function (method, params) {
|
|
71
|
+
var _this = this;
|
|
72
|
+
if (params === void 0) { params = []; }
|
|
73
|
+
if (!Array.isArray(params)) {
|
|
74
|
+
params = [params];
|
|
75
|
+
}
|
|
76
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
77
|
+
return new Promise(function (resolve, reject) {
|
|
78
|
+
var taskId = 'task-' + (0, common_1.objectIdHexString)();
|
|
79
|
+
_this._taskQueue.push({
|
|
80
|
+
type: 'task',
|
|
81
|
+
taskId: taskId,
|
|
82
|
+
method: method,
|
|
83
|
+
params: params,
|
|
84
|
+
messageId: 0,
|
|
85
|
+
userContext: {
|
|
86
|
+
user: 'Internal System'
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
_this._pendingTasks.set(taskId, {
|
|
90
|
+
timeout: null,
|
|
91
|
+
promise: { resolve: resolve, reject: reject }
|
|
92
|
+
});
|
|
93
|
+
if (_this._methodManager.getEnableDebug()) {
|
|
94
|
+
console.log(new Date(), 'Send Internal Promise', _this._taskQueue);
|
|
95
|
+
}
|
|
96
|
+
_this.dispatchQueue();
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Send a task internally without returning a promise.
|
|
101
|
+
*/
|
|
102
|
+
WorkerDispatcherManager.prototype.sendInternalTask = function (method, params) {
|
|
103
|
+
if (params === void 0) { params = []; }
|
|
104
|
+
if (!Array.isArray(params)) {
|
|
105
|
+
params = [params];
|
|
106
|
+
}
|
|
107
|
+
var taskId = 'task-' + (0, common_1.objectIdHexString)();
|
|
108
|
+
this._taskQueue.push({
|
|
109
|
+
type: 'task',
|
|
110
|
+
taskId: taskId,
|
|
111
|
+
method: method,
|
|
112
|
+
params: params,
|
|
113
|
+
messageId: 0,
|
|
114
|
+
userContext: {
|
|
115
|
+
user: 'Internal System'
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
if (this._methodManager.getEnableDebug()) {
|
|
119
|
+
console.log(new Date(), 'Send Internal Task', this._taskQueue);
|
|
120
|
+
}
|
|
121
|
+
this.dispatchQueue();
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* The main loop that assigns tasks from _taskQueue to any worker that has capacity.
|
|
125
|
+
*/
|
|
126
|
+
WorkerDispatcherManager.prototype.dispatchQueue = function () {
|
|
127
|
+
var _this = this;
|
|
128
|
+
if (!this._taskQueue.length) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
while (this._taskQueue.length > 0) {
|
|
132
|
+
var worker = this.findAvailableWorker();
|
|
133
|
+
if (!worker) {
|
|
134
|
+
setTimeout(function () {
|
|
135
|
+
_this.dispatchQueue();
|
|
136
|
+
}, 25);
|
|
137
|
+
if (this._methodManager.getEnableDebug()) {
|
|
138
|
+
console.log(new Date(), 'No Worker Available', JSON.stringify(this._workers, null, 2));
|
|
139
|
+
}
|
|
140
|
+
return; // no worker can take more tasks right now
|
|
141
|
+
}
|
|
142
|
+
if (this._methodManager.getEnableDebug()) {
|
|
143
|
+
console.log(new Date(), 'Worker Available', worker.id, worker.activeTasks);
|
|
144
|
+
}
|
|
145
|
+
// Remove from queue
|
|
146
|
+
var task = this._taskQueue.shift();
|
|
147
|
+
this.assignTaskToWorker(worker, task);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Returns the worker with the fewest activeTasks that is under maxConcurrency. Or null if none.
|
|
152
|
+
*/
|
|
153
|
+
WorkerDispatcherManager.prototype.findAvailableWorker = function () {
|
|
154
|
+
var _this = this;
|
|
155
|
+
var candidates = this._workers.filter(function (x) { return x.activeTasks.length < _this.MAX_CONCURRENCY; });
|
|
156
|
+
if (!candidates.length) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
candidates.sort(function (x, y) {
|
|
160
|
+
var totalX = x.activeTasks.map(function (a) { return a.weight; }).reduce(function (a, b) { return a + b; }, 0);
|
|
161
|
+
var totalY = y.activeTasks.map(function (a) { return a.weight; }).reduce(function (a, b) { return a + b; }, 0);
|
|
162
|
+
return totalX - totalY;
|
|
163
|
+
});
|
|
164
|
+
return candidates[0];
|
|
165
|
+
};
|
|
166
|
+
WorkerDispatcherManager.prototype.assignTaskToWorker = function (worker, task) {
|
|
167
|
+
var _this = this;
|
|
168
|
+
var method = this._methodManager.getMethod(task.method);
|
|
169
|
+
if (!method) {
|
|
170
|
+
console.error('Failed to send task to worker - Could not find method:', task.method);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
worker.activeTasks.push({
|
|
174
|
+
taskId: task.taskId,
|
|
175
|
+
weight: method && method.workerTaskWeight ? method.workerTaskWeight : 1
|
|
176
|
+
});
|
|
177
|
+
var payload = {
|
|
178
|
+
type: 'task',
|
|
179
|
+
taskId: task.taskId,
|
|
180
|
+
messageId: task.messageId,
|
|
181
|
+
method: task.method,
|
|
182
|
+
params: task.params,
|
|
183
|
+
userContext: task.userContext || {}
|
|
184
|
+
};
|
|
185
|
+
var timeoutHandle = setTimeout(function () {
|
|
186
|
+
var pending = _this._pendingTasks.get(task.taskId);
|
|
187
|
+
if (pending) {
|
|
188
|
+
if (pending.promise) {
|
|
189
|
+
pending.promise.reject('Task timed out after 2m in WorkerDispatcherManager for method: ' + task.method);
|
|
190
|
+
}
|
|
191
|
+
_this._pendingTasks.delete(task.taskId);
|
|
192
|
+
}
|
|
193
|
+
console.log(new Date(), 'TIMEOUT HIT', 'task', task.taskId, task.messageId, task.method, JSON.stringify(_this._workers.map(function (a) { return a.activeTasks; })));
|
|
194
|
+
worker.activeTasks = worker.activeTasks.filter(function (a) { return a.taskId !== task.taskId; });
|
|
195
|
+
if (task.userContext && task.userContext.id_ws) {
|
|
196
|
+
var timeoutRes = {
|
|
197
|
+
messageId: task.messageId,
|
|
198
|
+
hasError: true,
|
|
199
|
+
data: 'Task timed out after 2m in WorkerDispatcherManager for method: ' + task.method
|
|
200
|
+
};
|
|
201
|
+
var clientWS = _this._websocketManager.getWebSocket(task.userContext.id_ws);
|
|
202
|
+
if (clientWS) {
|
|
203
|
+
_this._websocketManager.send(clientWS, timeoutRes);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}, (1000 * 60 * 2));
|
|
207
|
+
// If we already stored a promise for this task (from sendInternalPromise), add the timeout now
|
|
208
|
+
var existing = this._pendingTasks.get(task.taskId);
|
|
209
|
+
if (!existing) {
|
|
210
|
+
existing = { timeout: null };
|
|
211
|
+
}
|
|
212
|
+
existing.timeout = timeoutHandle;
|
|
213
|
+
this._pendingTasks.set(task.taskId, existing);
|
|
214
|
+
try {
|
|
215
|
+
this.sendWorkerPayload(worker.ws, payload);
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
console.error('Failed to send task to worker:', err);
|
|
219
|
+
clearTimeout(timeoutHandle);
|
|
220
|
+
worker.activeTasks = worker.activeTasks.filter(function (a) { return a.taskId !== task.taskId; });
|
|
221
|
+
// Put task back in front
|
|
222
|
+
this._taskQueue.unshift(task);
|
|
223
|
+
this.dispatchQueue();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Handle messages coming back from a worker (like 'taskComplete').
|
|
228
|
+
*/
|
|
229
|
+
WorkerDispatcherManager.prototype.handleWorkerMessage = function (workerId, messageStr) {
|
|
230
|
+
var data;
|
|
231
|
+
try {
|
|
232
|
+
data = JSON.parse(messageStr, common_1.dateReviver);
|
|
233
|
+
}
|
|
234
|
+
catch (_a) {
|
|
235
|
+
console.error('Failed to parse worker message:', messageStr);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (data.type === 'taskComplete') {
|
|
239
|
+
var worker = this._workers.find(function (x) { return x.id === workerId; });
|
|
240
|
+
if (!worker) {
|
|
241
|
+
console.error('Unknown worker for taskComplete:', workerId);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
var taskId_1 = data.taskId, messageId = data.messageId, error = data.error, result = data.result;
|
|
245
|
+
worker.activeTasks = worker.activeTasks.filter(function (a) { return a.taskId !== taskId_1; });
|
|
246
|
+
var pendingTask = this._pendingTasks.get(taskId_1);
|
|
247
|
+
if (this._methodManager.getEnableDebug()) {
|
|
248
|
+
console.log(new Date(), 'Recv from Worker Server', data);
|
|
249
|
+
}
|
|
250
|
+
if (pendingTask) {
|
|
251
|
+
if (pendingTask.promise) {
|
|
252
|
+
if (error) {
|
|
253
|
+
pendingTask.promise.reject(result);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
pendingTask.promise.resolve(result);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
clearTimeout(pendingTask.timeout);
|
|
260
|
+
this._pendingTasks.delete(taskId_1);
|
|
261
|
+
}
|
|
262
|
+
// Look up original request if it came from a client
|
|
263
|
+
var clientReqId = this._clientRequests[taskId_1];
|
|
264
|
+
if (clientReqId) {
|
|
265
|
+
var res = {
|
|
266
|
+
messageId: messageId,
|
|
267
|
+
hasError: false,
|
|
268
|
+
data: result
|
|
269
|
+
};
|
|
270
|
+
if (error) {
|
|
271
|
+
res.hasError = true;
|
|
272
|
+
res.data = result;
|
|
273
|
+
}
|
|
274
|
+
var clientReqWS = this._websocketManager.getWebSocket(clientReqId);
|
|
275
|
+
if (clientReqWS) {
|
|
276
|
+
this._websocketManager.send(clientReqWS, res);
|
|
277
|
+
}
|
|
278
|
+
if (this._clientRequests[taskId_1]) {
|
|
279
|
+
delete this._clientRequests[taskId_1];
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Try to dispatch more from the queue
|
|
283
|
+
if (this._taskQueue.length) {
|
|
284
|
+
this.dispatchQueue();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
WorkerDispatcherManager.prototype.sendWorkerPayload = function (ws, payload) {
|
|
289
|
+
if (typeof payload !== 'string') {
|
|
290
|
+
payload = JSON.stringify(payload);
|
|
291
|
+
}
|
|
292
|
+
if (ws && ws.readyState === ws.OPEN) {
|
|
293
|
+
try {
|
|
294
|
+
ws.send(payload);
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
var task = JSON.parse(payload, common_1.dateReviver);
|
|
298
|
+
this._taskQueue.unshift(task);
|
|
299
|
+
this.dispatchQueue();
|
|
300
|
+
if (this._methodManager.getEnableDebug()) {
|
|
301
|
+
console.log(new Date(), 'Sending to Server', task);
|
|
302
|
+
}
|
|
303
|
+
this.disconnectWorker(ws['id_worker']);
|
|
304
|
+
ws.close();
|
|
305
|
+
console.error('Failed to send worker response:', err);
|
|
306
|
+
var pendingTask = this._pendingTasks.get(task.taskId);
|
|
307
|
+
if (pendingTask) {
|
|
308
|
+
clearTimeout(pendingTask.timeout);
|
|
309
|
+
this._pendingTasks.delete(task.taskId);
|
|
310
|
+
if (pendingTask.promise) {
|
|
311
|
+
pendingTask.promise.reject('Failed to send worker response: ' + (err === null || err === void 0 ? void 0 : err.toString()));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else if (ws) {
|
|
317
|
+
var task = JSON.parse(payload, common_1.dateReviver);
|
|
318
|
+
this._taskQueue.unshift(task);
|
|
319
|
+
this.dispatchQueue();
|
|
320
|
+
this.disconnectWorker(ws['id_worker']);
|
|
321
|
+
ws.close();
|
|
322
|
+
var pendingTask = this._pendingTasks.get(task.taskId);
|
|
323
|
+
if (pendingTask) {
|
|
324
|
+
clearTimeout(pendingTask.timeout);
|
|
325
|
+
this._pendingTasks.delete(task.taskId);
|
|
326
|
+
if (pendingTask.promise) {
|
|
327
|
+
pendingTask.promise.reject('Worker socket not open.');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
return WorkerDispatcherManager;
|
|
333
|
+
}());
|
|
334
|
+
exports.WorkerDispatcherManager = WorkerDispatcherManager;
|
|
335
|
+
|
|
2
336
|
//# 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","_websocketManager","_methodManager","isSafeShutdown","length","size","addWorker","ws","_this","push","id","activeTasks","setInterval","getEnableDebug","console","log","JSON","stringify","map","a","dispatchQueue","disconnectWorker","workerId","filter","w","sendClientTask","messageId","method","params","userContext","taskId","objectIdHexString","type","id_ws","sendInternalPromise","Array","isArray","Promise","resolve","reject","user","set","timeout","promise","Date","sendInternalTask","worker","findAvailableWorker","setTimeout","task","shift","assignTaskToWorker","candidates","x","sort","y","weight","reduce","b","getMethod","workerTaskWeight","payload","timeoutHandle","clientWS","pending","get","delete","timeoutRes","hasError","data","getWebSocket","send","existing","sendWorkerPayload","err","error","clearTimeout","unshift","handleWorkerMessage","messageStr","taskId_1","result","clientReqId","clientReqWS","parse","dateReviver","_a","find","pendingTask","res","readyState","OPEN","close","toString","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\tid: string;\n\tws: WebSocket.WebSocket;\n\tactiveTasks: { taskId: string; weight: number }[];\n}\n\ninterface PendingTask {\n\ttimeout: NodeJS.Timeout;\n\tpromise?: {\n\t\t// eslint-disable-next-line no-unused-vars\n\t\tresolve: (value: any) => void;\n\t\t// eslint-disable-next-line no-unused-vars\n\t\treject: (reason?: any) => void;\n\t};\n}\n\nexport class WorkerDispatcherManager {\n\tprivate _websocketManager: WebSocketManager;\n\tprivate _methodManager: MethodManager;\n\tprivate _workers: WorkerConnection[] = [];\n\tprivate _taskQueue: TaskPayload[] = [];\n\tprivate _clientRequests: { [taskId: string]: string } = {};\n\tprivate _pendingTasks: Map<string, PendingTask> = new Map();\n\n\tprivate MAX_CONCURRENCY = 10;\n\n\tconstructor() {}\n\n\tstatic create(websocketManager: WebSocketManager, methodManager: MethodManager) {\n\t\tconst workerDispatcherManager = new WorkerDispatcherManager();\n\t\tworkerDispatcherManager.initialize(websocketManager, methodManager);\n\t\treturn workerDispatcherManager;\n\t}\n\n\tpublic initialize(websocketManager: WebSocketManager, methodManager: MethodManager) {\n\t\tthis._websocketManager = websocketManager;\n\t\tthis._methodManager = methodManager;\n\t}\n\n\tpublic isSafeShutdown() {\n\t\treturn !this._taskQueue.length && !this._pendingTasks.size;\n\t}\n\n\tpublic addWorker(ws: WebSocket.WebSocket) {\n\t\tthis._workers.push({\n\t\t\tid: ws['id_worker'],\n\t\t\tws: ws,\n\t\t\tactiveTasks: []\n\t\t});\n\n\t\tsetInterval(() => {\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(JSON.stringify(this._workers.map(a => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: a.id,\n\t\t\t\t\t\tactiveTasks: a.activeTasks\n\t\t\t\t\t}\n\t\t\t\t}), null, 2));\n\t\t\t}\n\t\t}, 5000);\n\n\t\tif (this._taskQueue.length) {\n\t\t\tthis.dispatchQueue();\n\t\t}\n\t}\n\n\tpublic disconnectWorker(workerId: string) {\n\t\tthis._workers = this._workers.filter(w => w.id !== workerId);\n\t}\n\n\t/**\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\tthis._clientRequests[taskId] = userContext.id_ws;\n\t\t}\n\n\t\tthis.dispatchQueue();\n\t}\n\n\t/**\n\t * Same as sendInternalTask but returns a Promise so you can `await` it.\n\t */\n\tpublic sendInternalPromise(method: string, params: any[] = []): Promise<any> {\n\t\tif (!Array.isArray(params)) {\n\t\t\tparams = [params];\n\t\t}\n\n\t\t// eslint-disable-next-line no-restricted-syntax\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\t\tthis._taskQueue.push({\n\t\t\t\ttype: 'task',\n\t\t\t\ttaskId,\n\t\t\t\tmethod,\n\t\t\t\tparams,\n\t\t\t\tmessageId: 0,\n\t\t\t\tuserContext: {\n\t\t\t\t\tuser: 'Internal System'\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis._pendingTasks.set(taskId, {\n\t\t\t\ttimeout: null,\n\t\t\t\tpromise: { resolve, reject }\n\t\t\t});\n\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Send Internal Promise', this._taskQueue);\n\t\t\t}\n\n\t\t\tthis.dispatchQueue();\n\t\t});\n\t}\n\n\t/**\n\t * Send a task internally without returning a promise.\n\t */\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\tif (this._methodManager.getEnableDebug()) {\n\t\t\tconsole.log(new Date(), 'Send Internal Task', this._taskQueue);\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\n\t\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\t\tconsole.log(new Date(), 'No Worker Available', JSON.stringify(this._workers, null, 2));\n\t\t\t\t}\n\n\t\t\t\treturn; // no worker can take more tasks right now\n\t\t\t}\n\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Worker Available', worker.id, worker.activeTasks);\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\tcandidates.sort((x, y) => {\n\t\t\tlet totalX = x.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0);\n\t\t\tlet totalY = y.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0);\n\t\t\treturn totalX - totalY;\n\t\t});\n\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\tlet pending = this._pendingTasks.get(task.taskId);\n\t\t\t\n\t\t\tif (pending) {\n\t\t\t\tif (pending.promise) {\n\t\t\t\t\tpending.promise.reject('Task timed out after 2m in WorkerDispatcherManager for method: ' + task.method);\n\t\t\t\t}\n\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}, (1000 * 60 * 2));\n\n\t\t// If we already stored a promise for this task (from sendInternalPromise), add the timeout now\n\t\tlet existing = this._pendingTasks.get(task.taskId);\n\t\tif (!existing) {\n\t\t\texisting = { timeout: null };\n\t\t}\n\n\t\texisting.timeout = timeoutHandle;\n\t\tthis._pendingTasks.set(task.taskId, existing);\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\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== task.taskId);\n\n\t\t\t// Put task back in 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\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\tif (data.type === 'taskComplete') {\n\t\t\tlet worker = this._workers.find(x => x.id === workerId);\n\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\n\t\t\tlet { taskId, messageId, error, result } = data;\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== taskId);\n\n\t\t\tlet pendingTask = this._pendingTasks.get(taskId);\n\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Recv from Worker Server', data);\n\t\t\t}\n\n\t\t\tif (pendingTask) {\n\t\t\t\tif (pendingTask.promise) {\n\t\t\t\t\tif (error) {\n\t\t\t\t\t\tpendingTask.promise.reject(result);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tpendingTask.promise.resolve(result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\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 if it came from a client\n\t\t\tlet clientReqId = this._clientRequests[taskId];\n\n\t\t\tif (clientReqId) {\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\t\tif (typeof payload !== 'string') {\n\t\t\tpayload = JSON.stringify(payload);\n\t\t}\n\n\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\ttry {\n\t\t\t\tws.send(payload);\n\t\t\t}\n\t\t\tcatch (err) {\n\t\t\t\tlet task = JSON.parse(payload, dateReviver);\n\n\t\t\t\tthis._taskQueue.unshift(task);\n\t\t\t\tthis.dispatchQueue();\n\n\t\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\t\tconsole.log(new Date(), 'Sending to Server', task);\n\t\t\t\t}\n\n\t\t\t\tthis.disconnectWorker(ws['id_worker']);\n\t\t\t\tws.close();\n\t\t\t\tconsole.error('Failed to send worker response:', err);\n\n\t\t\t\tlet pendingTask = this._pendingTasks.get(task.taskId);\n\n\t\t\t\tif (pendingTask) {\n\t\t\t\t\tclearTimeout(pendingTask.timeout);\n\t\t\t\t\tthis._pendingTasks.delete(task.taskId);\n\n\t\t\t\t\tif (pendingTask.promise) {\n\t\t\t\t\t\tpendingTask.promise.reject('Failed to send worker response: ' + err?.toString());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (ws) {\n\t\t\tlet task = JSON.parse(payload, dateReviver);\n\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\t\t\tlet pendingTask = this._pendingTasks.get(task.taskId);\n\n\t\t\tif (pendingTask) {\n\t\t\t\tclearTimeout(pendingTask.timeout);\n\t\t\t\tthis._pendingTasks.delete(task.taskId);\n\n\t\t\t\tif (pendingTask.promise) {\n\t\t\t\t\tpendingTask.promise.reject('Worker socket not open.');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/managers/worker-dispatcher.manager.ts"],"names":[],"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\tid: string;\n\tws: WebSocket.WebSocket;\n\tactiveTasks: { taskId: string; weight: number }[];\n}\n\ninterface PendingTask {\n\ttimeout: NodeJS.Timeout;\n\tpromise?: {\n\t\t// eslint-disable-next-line no-unused-vars\n\t\tresolve: (value: any) => void;\n\t\t// eslint-disable-next-line no-unused-vars\n\t\treject: (reason?: any) => void;\n\t};\n}\n\nexport class WorkerDispatcherManager {\n\tprivate _websocketManager: WebSocketManager;\n\tprivate _methodManager: MethodManager;\n\tprivate _workers: WorkerConnection[] = [];\n\tprivate _taskQueue: TaskPayload[] = [];\n\tprivate _clientRequests: { [taskId: string]: string } = {};\n\tprivate _pendingTasks: Map<string, PendingTask> = new Map();\n\n\tprivate MAX_CONCURRENCY = 10;\n\n\tconstructor() {}\n\n\tstatic create(websocketManager: WebSocketManager, methodManager: MethodManager) {\n\t\tconst workerDispatcherManager = new WorkerDispatcherManager();\n\t\tworkerDispatcherManager.initialize(websocketManager, methodManager);\n\t\treturn workerDispatcherManager;\n\t}\n\n\tpublic initialize(websocketManager: WebSocketManager, methodManager: MethodManager) {\n\t\tthis._websocketManager = websocketManager;\n\t\tthis._methodManager = methodManager;\n\t}\n\n\tpublic isSafeShutdown() {\n\t\treturn !this._taskQueue.length && !this._pendingTasks.size;\n\t}\n\n\tpublic addWorker(ws: WebSocket.WebSocket) {\n\t\tthis._workers.push({\n\t\t\tid: ws['id_worker'],\n\t\t\tws: ws,\n\t\t\tactiveTasks: []\n\t\t});\n\n\t\tsetInterval(() => {\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(JSON.stringify(this._workers.map(a => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: a.id,\n\t\t\t\t\t\tactiveTasks: a.activeTasks\n\t\t\t\t\t}\n\t\t\t\t}), null, 2));\n\t\t\t}\n\t\t}, 5000);\n\n\t\tif (this._taskQueue.length) {\n\t\t\tthis.dispatchQueue();\n\t\t}\n\t}\n\n\tpublic disconnectWorker(workerId: string) {\n\t\tthis._workers = this._workers.filter(w => w.id !== workerId);\n\t}\n\n\t/**\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\tthis._clientRequests[taskId] = userContext.id_ws;\n\t\t}\n\n\t\tthis.dispatchQueue();\n\t}\n\n\t/**\n\t * Same as sendInternalTask but returns a Promise so you can `await` it.\n\t */\n\tpublic sendInternalPromise(method: string, params: any[] = []): Promise<any> {\n\t\tif (!Array.isArray(params)) {\n\t\t\tparams = [params];\n\t\t}\n\n\t\t// eslint-disable-next-line no-restricted-syntax\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\t\tthis._taskQueue.push({\n\t\t\t\ttype: 'task',\n\t\t\t\ttaskId,\n\t\t\t\tmethod,\n\t\t\t\tparams,\n\t\t\t\tmessageId: 0,\n\t\t\t\tuserContext: {\n\t\t\t\t\tuser: 'Internal System'\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis._pendingTasks.set(taskId, {\n\t\t\t\ttimeout: null,\n\t\t\t\tpromise: { resolve, reject }\n\t\t\t});\n\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Send Internal Promise', this._taskQueue);\n\t\t\t}\n\n\t\t\tthis.dispatchQueue();\n\t\t});\n\t}\n\n\t/**\n\t * Send a task internally without returning a promise.\n\t */\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\tif (this._methodManager.getEnableDebug()) {\n\t\t\tconsole.log(new Date(), 'Send Internal Task', this._taskQueue);\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\n\t\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\t\tconsole.log(new Date(), 'No Worker Available', JSON.stringify(this._workers, null, 2));\n\t\t\t\t}\n\n\t\t\t\treturn; // no worker can take more tasks right now\n\t\t\t}\n\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Worker Available', worker.id, worker.activeTasks);\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\tcandidates.sort((x, y) => {\n\t\t\tlet totalX = x.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0);\n\t\t\tlet totalY = y.activeTasks.map(a => a.weight).reduce((a, b) => a + b, 0);\n\t\t\treturn totalX - totalY;\n\t\t});\n\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\tlet pending = this._pendingTasks.get(task.taskId);\n\t\t\t\n\t\t\tif (pending) {\n\t\t\t\tif (pending.promise) {\n\t\t\t\t\tpending.promise.reject('Task timed out after 2m in WorkerDispatcherManager for method: ' + task.method);\n\t\t\t\t}\n\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}, (1000 * 60 * 2));\n\n\t\t// If we already stored a promise for this task (from sendInternalPromise), add the timeout now\n\t\tlet existing = this._pendingTasks.get(task.taskId);\n\t\tif (!existing) {\n\t\t\texisting = { timeout: null };\n\t\t}\n\n\t\texisting.timeout = timeoutHandle;\n\t\tthis._pendingTasks.set(task.taskId, existing);\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\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== task.taskId);\n\n\t\t\t// Put task back in 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\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\tif (data.type === 'taskComplete') {\n\t\t\tlet worker = this._workers.find(x => x.id === workerId);\n\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\n\t\t\tlet { taskId, messageId, error, result } = data;\n\t\t\tworker.activeTasks = worker.activeTasks.filter(a => a.taskId !== taskId);\n\n\t\t\tlet pendingTask = this._pendingTasks.get(taskId);\n\n\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Recv from Worker Server', data);\n\t\t\t}\n\n\t\t\tif (pendingTask) {\n\t\t\t\tif (pendingTask.promise) {\n\t\t\t\t\tif (error) {\n\t\t\t\t\t\tpendingTask.promise.reject(result);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tpendingTask.promise.resolve(result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\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 if it came from a client\n\t\t\tlet clientReqId = this._clientRequests[taskId];\n\n\t\t\tif (clientReqId) {\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\t\tif (typeof payload !== 'string') {\n\t\t\tpayload = JSON.stringify(payload);\n\t\t}\n\n\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\ttry {\n\t\t\t\tws.send(payload);\n\t\t\t}\n\t\t\tcatch (err) {\n\t\t\t\tlet task = JSON.parse(payload, dateReviver);\n\n\t\t\t\tthis._taskQueue.unshift(task);\n\t\t\t\tthis.dispatchQueue();\n\n\t\t\t\tif (this._methodManager.getEnableDebug()) {\n\t\t\t\t\tconsole.log(new Date(), 'Sending to Server', task);\n\t\t\t\t}\n\n\t\t\t\tthis.disconnectWorker(ws['id_worker']);\n\t\t\t\tws.close();\n\t\t\t\tconsole.error('Failed to send worker response:', err);\n\n\t\t\t\tlet pendingTask = this._pendingTasks.get(task.taskId);\n\n\t\t\t\tif (pendingTask) {\n\t\t\t\t\tclearTimeout(pendingTask.timeout);\n\t\t\t\t\tthis._pendingTasks.delete(task.taskId);\n\n\t\t\t\t\tif (pendingTask.promise) {\n\t\t\t\t\t\tpendingTask.promise.reject('Failed to send worker response: ' + err?.toString());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (ws) {\n\t\t\tlet task = JSON.parse(payload, dateReviver);\n\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\t\t\tlet pendingTask = this._pendingTasks.get(task.taskId);\n\n\t\t\tif (pendingTask) {\n\t\t\t\tclearTimeout(pendingTask.timeout);\n\t\t\t\tthis._pendingTasks.delete(task.taskId);\n\n\t\t\t\tif (pendingTask.promise) {\n\t\t\t\t\tpendingTask.promise.reject('Worker socket not open.');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|