@coherentglobal/wasm-runner 0.0.103 → 0.1.19
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/README.md +137 -222
- package/dist/CancellationToken.js.map +1 -1
- package/dist/browser/logger.js.map +1 -1
- package/dist/browser/template/main.template.js +1 -1
- package/dist/browser/template/main.template.js.map +1 -1
- package/dist/browser/template/runtime.template.js.map +1 -1
- package/dist/browser/template/worker.template.js +7 -4
- package/dist/browser/template/worker.template.js.map +1 -1
- package/dist/browser/template.js +1 -1
- package/dist/browser/template.js.map +1 -1
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +6 -6
- package/dist/browser.js.map +1 -1
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +14 -0
- package/dist/constants.js.map +1 -0
- package/dist/error.d.ts +5 -0
- package/dist/error.js +13 -3
- package/dist/error.js.map +1 -1
- package/dist/mockConstants.d.ts +5 -0
- package/dist/mockConstants.js +14 -0
- package/dist/mockConstants.js.map +1 -0
- package/dist/node/logger.d.ts +1 -4
- package/dist/node/logger.js +1 -1
- package/dist/node/logger.js.map +1 -1
- package/dist/node/logger.ts +1 -1
- package/dist/node/template/main.template.ejs +126 -86
- package/dist/node/threads/mockWorkerThread.d.ts +28 -0
- package/dist/node/threads/mockWorkerThread.js +89 -0
- package/dist/node/threads/mockWorkerThread.js.map +1 -0
- package/dist/node/threads/workerPool.d.ts +17 -0
- package/dist/node/threads/workerPool.js +27 -0
- package/dist/node/threads/workerPool.js.map +1 -0
- package/dist/node/threads/workerPool.ts +38 -0
- package/dist/node/threads/workerThread.d.ts +31 -0
- package/dist/node/threads/workerThread.js +91 -0
- package/dist/node/threads/workerThread.js.map +1 -0
- package/dist/node/threads/workerThread.ts +92 -0
- package/dist/node.d.ts +36 -26
- package/dist/node.js +334 -62
- package/dist/node.js.map +1 -1
- package/dist/responseTimeMetric.d.ts +16 -0
- package/dist/responseTimeMetric.js +56 -0
- package/dist/responseTimeMetric.js.map +1 -0
- package/dist/serializer/columnarSerializer.d.ts +3 -2
- package/dist/serializer/columnarSerializer.js +10 -1
- package/dist/serializer/columnarSerializer.js.map +1 -1
- package/dist/types.d.ts +41 -2
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +27 -0
- package/dist/utils.js +49 -13
- package/dist/utils.js.map +1 -1
- package/package.json +8 -5
package/dist/node.js
CHANGED
|
@@ -51,10 +51,14 @@ const fs_1 = __importStar(require("fs"));
|
|
|
51
51
|
const path_1 = __importDefault(require("path"));
|
|
52
52
|
const util_1 = require("util");
|
|
53
53
|
const got_1 = __importDefault(require("got"));
|
|
54
|
-
const
|
|
54
|
+
const semver_1 = __importDefault(require("semver"));
|
|
55
|
+
const workerPool_1 = __importDefault(require("./node/threads/workerPool"));
|
|
55
56
|
const utils = __importStar(require("./utils"));
|
|
57
|
+
const types_1 = require("./types");
|
|
56
58
|
const error_1 = __importDefault(require("./error"));
|
|
57
59
|
const node_os_1 = require("node:os");
|
|
60
|
+
const constants_1 = require("./constants");
|
|
61
|
+
const responseTimeMetric_1 = __importDefault(require("./responseTimeMetric"));
|
|
58
62
|
/* istanbul ignore next */
|
|
59
63
|
var columnarSerializer_1 = require("./serializer/columnarSerializer");
|
|
60
64
|
Object.defineProperty(exports, "ColumnarSerializer", { enumerable: true, get: function () { return columnarSerializer_1.ColumnarSerializer; } });
|
|
@@ -92,6 +96,7 @@ const unzipFiles = (id, url, workerFolder) => {
|
|
|
92
96
|
let data;
|
|
93
97
|
let metadata;
|
|
94
98
|
let formspec;
|
|
99
|
+
let compilerLog;
|
|
95
100
|
// @ts-ignore
|
|
96
101
|
const stream = fs_1.default.createReadStream(url).pipe((0, unzipper_1.Parse)());
|
|
97
102
|
return new Promise((resolve, reject) => {
|
|
@@ -115,6 +120,9 @@ const unzipFiles = (id, url, workerFolder) => {
|
|
|
115
120
|
if (entry.path.toLowerCase().indexOf("_jsonformspec.json") > -1) {
|
|
116
121
|
formspec = fileName;
|
|
117
122
|
}
|
|
123
|
+
if (entry.path.toLowerCase().indexOf("_compilerlog.json") > -1) {
|
|
124
|
+
compilerLog = fileName;
|
|
125
|
+
}
|
|
118
126
|
return entry.pipe(writeStream);
|
|
119
127
|
}
|
|
120
128
|
return entry.autodrain();
|
|
@@ -131,6 +139,7 @@ const unzipFiles = (id, url, workerFolder) => {
|
|
|
131
139
|
data,
|
|
132
140
|
metadata,
|
|
133
141
|
formspec,
|
|
142
|
+
compilerLog,
|
|
134
143
|
});
|
|
135
144
|
});
|
|
136
145
|
stream.on("error", (error) => reject(error));
|
|
@@ -140,18 +149,11 @@ const template = ejs_1.default.compile(fs_1.default.readFileSync(path_1.default.
|
|
|
140
149
|
encoding: "utf8",
|
|
141
150
|
flag: "r",
|
|
142
151
|
}), { async: false });
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
*/
|
|
149
|
-
/**
|
|
150
|
-
* Input object
|
|
151
|
-
* @typedef {Object} InputObject
|
|
152
|
-
* @property {Object} request_data - Request input date
|
|
153
|
-
* @property {Object} request_meta - Request input meta
|
|
154
|
-
*/
|
|
152
|
+
const delay = (time) => {
|
|
153
|
+
return new Promise((res) => {
|
|
154
|
+
setTimeout(res, time);
|
|
155
|
+
});
|
|
156
|
+
};
|
|
155
157
|
/**
|
|
156
158
|
* WasmRunner class, responsible for managing model and it's lifecycle
|
|
157
159
|
*
|
|
@@ -165,21 +167,30 @@ class WasmRunner {
|
|
|
165
167
|
*
|
|
166
168
|
* @param {RunnerConfig} wasmRunnerConfig
|
|
167
169
|
*/
|
|
168
|
-
constructor(wasmRunnerConfig, externalResolverModule = "", license = "") {
|
|
170
|
+
constructor(wasmRunnerConfig, externalResolverModule = "", options = {}, license = "") {
|
|
171
|
+
let baseTmpDir = null;
|
|
172
|
+
if (process.env.DEV_DEBUG_TMP_PATH) {
|
|
173
|
+
baseTmpDir = path_1.default.join(process.cwd(), process.env.DEV_DEBUG_TMP_PATH);
|
|
174
|
+
}
|
|
169
175
|
this._tempWorkerFolder = tmp_1.default.dirSync({
|
|
170
176
|
prefix: "wasmserver_worker",
|
|
171
177
|
// @ts-ignore
|
|
172
178
|
mode: 0o750,
|
|
179
|
+
tmpdir: baseTmpDir,
|
|
173
180
|
});
|
|
174
181
|
this._tempModelFolder = tmp_1.default.dirSync({
|
|
175
182
|
prefix: "wasmserver_model",
|
|
176
183
|
// @ts-ignore
|
|
177
184
|
mode: 0o750,
|
|
185
|
+
tmpdir: baseTmpDir,
|
|
178
186
|
});
|
|
179
187
|
this.license = license;
|
|
180
|
-
this.
|
|
181
|
-
|
|
188
|
+
this.initializingModels = [];
|
|
189
|
+
this.externalResolverModule = externalResolverModule
|
|
190
|
+
? require(useCorrectPath(require.resolve(externalResolverModule)))
|
|
191
|
+
: require(require.resolve("./defaultExternalResolver"));
|
|
182
192
|
this.models = [];
|
|
193
|
+
this.options = options;
|
|
183
194
|
if (!utils.isEmpty(wasmRunnerConfig)) {
|
|
184
195
|
if (Array.isArray(wasmRunnerConfig)) {
|
|
185
196
|
this.models = wasmRunnerConfig.map((wsconfig) => ({
|
|
@@ -204,20 +215,24 @@ class WasmRunner {
|
|
|
204
215
|
* @function initialize
|
|
205
216
|
*/
|
|
206
217
|
/* istanbul ignore next */
|
|
207
|
-
initialize(
|
|
208
|
-
return __awaiter(this,
|
|
218
|
+
initialize() {
|
|
219
|
+
return __awaiter(this, arguments, void 0, function* (license = "") {
|
|
220
|
+
if (this.options.compatibilityCheckEnabled) {
|
|
221
|
+
this.safeCompiler = yield this.getSafeCompilerVersion(this.options.runnerVersion);
|
|
222
|
+
}
|
|
209
223
|
yield Promise.all(this.models.map((m) => __awaiter(this, void 0, void 0, function* () {
|
|
210
224
|
return this._initializeModelInstance(m);
|
|
211
225
|
})));
|
|
212
226
|
});
|
|
213
227
|
}
|
|
214
228
|
/* istanbul ignore next */
|
|
215
|
-
_createModelInstance(
|
|
216
|
-
return __awaiter(this,
|
|
229
|
+
_createModelInstance(id_1, url_1, workerFolder_1) {
|
|
230
|
+
return __awaiter(this, arguments, void 0, function* (id, url, workerFolder, size = 1) {
|
|
231
|
+
const workerSize = size || 1;
|
|
217
232
|
logger_1.default.debug({
|
|
218
233
|
TimeStamp: Date.now(),
|
|
219
234
|
EventType: "Runner._createModelInstance",
|
|
220
|
-
size:
|
|
235
|
+
size: workerSize,
|
|
221
236
|
ModelId: id,
|
|
222
237
|
});
|
|
223
238
|
const tempFolder = path_1.default.join(workerFolder, `${id}-${Date.now()}`);
|
|
@@ -235,6 +250,11 @@ class WasmRunner {
|
|
|
235
250
|
});
|
|
236
251
|
const modelName = id;
|
|
237
252
|
yield replaceRegexInFile(modelPack.js, `wasmBinaryFile="${path_1.default.basename(modelPack.wasm)}"`, `scriptDirectory="";wasmBinaryFile="${modelPack.wasm}"`);
|
|
253
|
+
const replaceIsFileURLFunc = "function isFileURI(filename) { if(typeof process !== undefined && process.versions && process.versions.node) { return true; }";
|
|
254
|
+
yield replaceRegexInFile(modelPack.js, "function isFileURI(filename) {", replaceIsFileURLFunc);
|
|
255
|
+
yield replaceRegexInFile(modelPack.js, "function isFileURI(filename){", replaceIsFileURLFunc);
|
|
256
|
+
// Remove `new URL()` since `isFileURI` will always be true for Node
|
|
257
|
+
yield replaceRegexInFile(modelPack.js, /\s*isFileURI\s*\(\s*filename\s*\)\s*\?\s*new\s*URL\s*\(\s*filename\s*\)\s*:\s*/g, "");
|
|
238
258
|
if (modelPack.data) {
|
|
239
259
|
yield replaceRegexInFile(modelPack.js, `"${path_1.default.basename(modelPack.data)}"`, `"${modelPack.data}"`);
|
|
240
260
|
yield replaceRegexInFile(modelPack.js, `"${path_1.default.basename(modelPack.data)}"`, `"${modelPack.data}"`);
|
|
@@ -242,10 +262,13 @@ class WasmRunner {
|
|
|
242
262
|
yield replaceRegexInFile(modelPack.js, `"${path_1.default.basename(modelPack.data)}"`, `"${modelPack.data}"`);
|
|
243
263
|
}
|
|
244
264
|
// Prepare File Paths
|
|
245
|
-
const externalResolverPath = useCorrectPath(this.externalResolverModule);
|
|
265
|
+
// const externalResolverPath = useCorrectPath(this.externalResolverModule);
|
|
246
266
|
const loggerPath = useCorrectPath(process.env.NODE_ENV === "test"
|
|
247
267
|
? require.resolve("./node/mockLogger.js")
|
|
248
268
|
: require.resolve("./node/logger"));
|
|
269
|
+
const workerThread = useCorrectPath(process.env.NODE_ENV === "test"
|
|
270
|
+
? require.resolve("./node/threads/mockWorkerThread.js")
|
|
271
|
+
: require.resolve("./node/threads/workerThread"));
|
|
249
272
|
let metadata = "undefined";
|
|
250
273
|
if (!utils.isEmpty(modelPack.metadata)) {
|
|
251
274
|
const metadataPath = useCorrectPath(require.resolve(modelPack.metadata));
|
|
@@ -256,6 +279,14 @@ class WasmRunner {
|
|
|
256
279
|
const formSpecPath = useCorrectPath(require.resolve(modelPack.formspec));
|
|
257
280
|
formspec = `require("${formSpecPath}")`;
|
|
258
281
|
}
|
|
282
|
+
let compilerVersion = "undefined";
|
|
283
|
+
let compatibilityStatus = "undefined";
|
|
284
|
+
compilerVersion = !utils.isEmpty(modelPack.compilerLog)
|
|
285
|
+
? yield this.getNeuronCompilerVersion(`"${modelPack.compilerLog}"`)
|
|
286
|
+
: undefined;
|
|
287
|
+
if (this.options.compatibilityCheckEnabled) {
|
|
288
|
+
compatibilityStatus = yield this.checkCompilerVersionCompatibility(compilerVersion);
|
|
289
|
+
}
|
|
259
290
|
const fileContent = template({
|
|
260
291
|
runtime: modelPack.js.replace(".js", ""),
|
|
261
292
|
model: modelPack.wasm,
|
|
@@ -263,8 +294,8 @@ class WasmRunner {
|
|
|
263
294
|
formspec,
|
|
264
295
|
modelName,
|
|
265
296
|
modules: {
|
|
266
|
-
externalResolver: externalResolverPath,
|
|
267
297
|
logger: loggerPath,
|
|
298
|
+
workerThread: workerThread,
|
|
268
299
|
},
|
|
269
300
|
});
|
|
270
301
|
const workerPath = path_1.default.join(tempFolder, `worker-${id}.js`);
|
|
@@ -274,26 +305,88 @@ class WasmRunner {
|
|
|
274
305
|
EventType: "Runner.CreateTemplates",
|
|
275
306
|
ModelId: id,
|
|
276
307
|
});
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
308
|
+
let workerPool;
|
|
309
|
+
/**
|
|
310
|
+
* Processes the requests from Worker thread. Interprets the request
|
|
311
|
+
* `type` and implement necessary logic and returns the result.
|
|
312
|
+
*
|
|
313
|
+
* @param {Object} requestData
|
|
314
|
+
* Event details from Worker thread.
|
|
315
|
+
*/
|
|
316
|
+
const processWorkerThreadRequest = (requestData) => __awaiter(this, void 0, void 0, function* () {
|
|
317
|
+
const { type, payload, context, threadId } = requestData;
|
|
318
|
+
// Worker request of model execution on main thread.
|
|
319
|
+
if (type === constants_1.THREAD_EVENT_TYPES.REQUEST_EXECUTE) {
|
|
320
|
+
try {
|
|
321
|
+
// Callback the resolver function
|
|
322
|
+
const result = yield this.externalResolverModule.sparkService(payload, context);
|
|
323
|
+
// Send back the response to worker thread
|
|
324
|
+
workerPool.postMessage({
|
|
325
|
+
payload: result,
|
|
326
|
+
type: constants_1.THREAD_EVENT_TYPES.RESPONSE,
|
|
327
|
+
threadId,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
catch (e) {
|
|
331
|
+
// Send back the error to worker thread
|
|
332
|
+
workerPool.postMessage({
|
|
333
|
+
payload: e,
|
|
334
|
+
type: constants_1.THREAD_EVENT_TYPES.ERROR,
|
|
335
|
+
threadId,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
const workerName = path_1.default.basename(modelPack.js, path_1.default.extname(modelPack.js)) || "";
|
|
341
|
+
workerPool = new workerPool_1.default(workerSize, workerPath, {
|
|
342
|
+
errorHandler: (e) => logger_1.default.error("Worker Error: ", e),
|
|
343
|
+
onlineHandler: () => logger_1.default.info(`Worker ${id} online`),
|
|
344
|
+
// Receive messages from worker here
|
|
345
|
+
messageHandler: processWorkerThreadRequest,
|
|
346
|
+
workerOptions: {
|
|
347
|
+
name: workerName,
|
|
348
|
+
},
|
|
349
|
+
enableTasksQueue: true
|
|
280
350
|
});
|
|
281
351
|
logger_1.default.debug({
|
|
282
352
|
TimeStamp: Date.now(),
|
|
283
353
|
EventType: "Runner.ModelInitialize",
|
|
284
354
|
ModelId: id,
|
|
285
355
|
});
|
|
356
|
+
workerPool.start();
|
|
286
357
|
return new Promise((resolve, reject) => {
|
|
287
358
|
let limit = 0;
|
|
359
|
+
let readyCount = workerSize;
|
|
360
|
+
const stats = {};
|
|
288
361
|
const checkModelStatus = () => __awaiter(this, void 0, void 0, function* () {
|
|
289
|
-
|
|
290
|
-
|
|
362
|
+
var _a;
|
|
363
|
+
const readyRes = yield workerPool.execute("isReady");
|
|
364
|
+
if (readyRes && !stats[readyRes.threadId]) {
|
|
365
|
+
stats[readyRes.threadId] = {
|
|
366
|
+
init_memory: readyRes.memoryUsage,
|
|
367
|
+
init_time_ms: readyRes.time,
|
|
368
|
+
ready_ts: ((_a = readyRes.payload) === null || _a === void 0 ? void 0 : _a.readyTs) || readyRes.readyTs,
|
|
369
|
+
peak_memory: readyRes.memoryUsage,
|
|
370
|
+
last_execute_consume_memory: readyRes.memoryUsage
|
|
371
|
+
};
|
|
372
|
+
readyCount = readyCount - 1;
|
|
291
373
|
logger_1.default.debug({
|
|
292
374
|
TimeStamp: Date.now(),
|
|
293
375
|
EventType: "Runner.ModelInitialize.Completed",
|
|
294
376
|
ModelId: id,
|
|
295
377
|
});
|
|
296
|
-
|
|
378
|
+
if (readyCount === 0) {
|
|
379
|
+
resolve({
|
|
380
|
+
instance: workerPool,
|
|
381
|
+
compilerVersion,
|
|
382
|
+
compatibilityStatus,
|
|
383
|
+
size: workerSize,
|
|
384
|
+
stats: stats
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
setTimeout(checkModelStatus, 1);
|
|
389
|
+
}
|
|
297
390
|
}
|
|
298
391
|
else if (limit >= 2000) {
|
|
299
392
|
// 1 second
|
|
@@ -313,15 +406,23 @@ class WasmRunner {
|
|
|
313
406
|
_initializeModelInstance(m) {
|
|
314
407
|
return __awaiter(this, void 0, void 0, function* () {
|
|
315
408
|
if (utils.isHttpURL(m.url)) {
|
|
316
|
-
const instance = yield this._createModelInstanceFromURL(m.id, m.url, this._tempWorkerFolder.name, this._tempModelFolder.name, m.size);
|
|
409
|
+
const { instance, compilerVersion, compatibilityStatus, stats } = yield this._createModelInstanceFromURL(m.id, m.url, this._tempWorkerFolder.name, this._tempModelFolder.name, m.size);
|
|
317
410
|
m.ready = true;
|
|
318
411
|
m.worker = instance;
|
|
412
|
+
m.compatibility_status = compatibilityStatus;
|
|
413
|
+
m.compilerVersion = compilerVersion;
|
|
414
|
+
m.stats = stats;
|
|
415
|
+
m.responseTimeMetrics = new responseTimeMetric_1.default();
|
|
319
416
|
return Promise.resolve();
|
|
320
417
|
}
|
|
321
418
|
if (yield utils.isPath(m.url)) {
|
|
322
|
-
const instance = yield this._createModelInstance(m.id, m.url, this._tempWorkerFolder.name, m.size);
|
|
419
|
+
const { instance, compilerVersion, compatibilityStatus, stats } = yield this._createModelInstance(m.id, m.url, this._tempWorkerFolder.name, m.size);
|
|
323
420
|
m.ready = true;
|
|
324
421
|
m.worker = instance;
|
|
422
|
+
m.compatibility_status = compatibilityStatus;
|
|
423
|
+
m.compilerVersion = compilerVersion;
|
|
424
|
+
m.stats = stats;
|
|
425
|
+
m.responseTimeMetrics = new responseTimeMetric_1.default();
|
|
325
426
|
return Promise.resolve();
|
|
326
427
|
}
|
|
327
428
|
if (Buffer.isBuffer(m.url)) {
|
|
@@ -329,9 +430,13 @@ class WasmRunner {
|
|
|
329
430
|
const modelPath = path_1.default.join(this._tempWorkerFolder.name, `${m.id}.zip`);
|
|
330
431
|
const fileWriterStream = (0, fs_1.createWriteStream)(modelPath);
|
|
331
432
|
yield pipeline(model, fileWriterStream);
|
|
332
|
-
const instance = yield this._createModelInstance(m.id, modelPath, this._tempWorkerFolder.name, m.size);
|
|
433
|
+
const { instance, compilerVersion, compatibilityStatus, stats } = yield this._createModelInstance(m.id, modelPath, this._tempWorkerFolder.name, m.size);
|
|
333
434
|
m.ready = true;
|
|
334
435
|
m.worker = instance;
|
|
436
|
+
m.compatibility_status = compatibilityStatus;
|
|
437
|
+
m.compilerVersion = compilerVersion;
|
|
438
|
+
m.stats = stats;
|
|
439
|
+
m.responseTimeMetrics = new responseTimeMetric_1.default();
|
|
335
440
|
return Promise.resolve();
|
|
336
441
|
}
|
|
337
442
|
});
|
|
@@ -353,35 +458,70 @@ class WasmRunner {
|
|
|
353
458
|
});
|
|
354
459
|
}
|
|
355
460
|
/**
|
|
356
|
-
* Append and
|
|
461
|
+
* Append and initialize model in preparation for the `execute()`.
|
|
462
|
+
*
|
|
357
463
|
* @param {ModelConfig} modelConfig
|
|
358
|
-
*
|
|
464
|
+
* Model details like version_id as `id` and zip path as `url`.
|
|
465
|
+
*
|
|
466
|
+
* @returns {Promise<void>}
|
|
359
467
|
*/
|
|
360
468
|
append(modelConfig) {
|
|
361
469
|
return __awaiter(this, void 0, void 0, function* () {
|
|
362
|
-
if (this.
|
|
363
|
-
|
|
470
|
+
if (this.options.compatibilityCheckEnabled) {
|
|
471
|
+
this.safeCompiler = yield this.getSafeCompilerVersion(this.options.runnerVersion);
|
|
472
|
+
}
|
|
473
|
+
if (!this.isExist(modelConfig.id)) {
|
|
474
|
+
const model = {
|
|
475
|
+
id: modelConfig.id,
|
|
476
|
+
url: modelConfig.url,
|
|
477
|
+
size: modelConfig.size,
|
|
478
|
+
busy: 0,
|
|
479
|
+
};
|
|
480
|
+
if (!this.isExist(modelConfig.id)) {
|
|
481
|
+
if (this.initializingModels.findIndex((im) => im === modelConfig.id) ===
|
|
482
|
+
-1) {
|
|
483
|
+
try {
|
|
484
|
+
this.initializingModels.push(modelConfig.id);
|
|
485
|
+
yield this._initializeModelInstance(model);
|
|
486
|
+
this.models.push(model);
|
|
487
|
+
}
|
|
488
|
+
catch (e) {
|
|
489
|
+
throw e;
|
|
490
|
+
}
|
|
491
|
+
finally {
|
|
492
|
+
this.initializingModels = this.initializingModels.filter((im) => im !== modelConfig.id);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
const maxRetry = 600;
|
|
497
|
+
let retry = 0;
|
|
498
|
+
while (this.initializingModels.findIndex((im) => im === modelConfig.id) >
|
|
499
|
+
-1 &&
|
|
500
|
+
retry < maxRetry) {
|
|
501
|
+
yield delay(100);
|
|
502
|
+
retry++;
|
|
503
|
+
}
|
|
504
|
+
if (retry >= maxRetry || !this.isExist(modelConfig.id)) {
|
|
505
|
+
throw new error_1.default.ModelInitializationError(modelConfig.id);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
364
509
|
}
|
|
365
|
-
const model = {
|
|
366
|
-
id: modelConfig.id,
|
|
367
|
-
url: modelConfig.url,
|
|
368
|
-
size: modelConfig.size,
|
|
369
|
-
busy: 0,
|
|
370
|
-
};
|
|
371
|
-
yield this._initializeModelInstance(model);
|
|
372
|
-
this.models.push(model);
|
|
373
510
|
});
|
|
374
511
|
}
|
|
375
512
|
/**
|
|
376
|
-
* Remove model from
|
|
377
|
-
*
|
|
378
|
-
* @
|
|
513
|
+
* Remove model from the list of initialized model useful for GC.
|
|
514
|
+
*
|
|
515
|
+
* @param {String} id
|
|
516
|
+
* ID of the model that needs to be removed.
|
|
517
|
+
*
|
|
518
|
+
* @returns {Promise<void>}
|
|
379
519
|
*/
|
|
380
520
|
remove(id) {
|
|
381
521
|
return __awaiter(this, void 0, void 0, function* () {
|
|
382
522
|
if (this.isExist(id)) {
|
|
383
523
|
const model = this.models.find((m) => m.id === id);
|
|
384
|
-
yield model.worker.
|
|
524
|
+
yield model.worker.execute("destroy");
|
|
385
525
|
model.worker.destroy();
|
|
386
526
|
delete model.worker;
|
|
387
527
|
this.models = this.models.filter((m) => m.id !== id);
|
|
@@ -442,10 +582,21 @@ class WasmRunner {
|
|
|
442
582
|
throw new error_1.default.ModelInitializationError(id);
|
|
443
583
|
return model;
|
|
444
584
|
}
|
|
585
|
+
getModelSize(id) {
|
|
586
|
+
const model = this._getModel(id);
|
|
587
|
+
return model.size || 1;
|
|
588
|
+
}
|
|
589
|
+
getModelCompilerVersion(id) {
|
|
590
|
+
const model = this._getModel(id);
|
|
591
|
+
if (model.compilerVersion && model.compilerVersion !== 'undefined') {
|
|
592
|
+
return model.compilerVersion;
|
|
593
|
+
}
|
|
594
|
+
return undefined;
|
|
595
|
+
}
|
|
445
596
|
/**
|
|
446
597
|
* Check if model existed
|
|
447
598
|
* @param {string} id Model id
|
|
448
|
-
* @returns boolean
|
|
599
|
+
* @returns {boolean}
|
|
449
600
|
*/
|
|
450
601
|
isExist(id) {
|
|
451
602
|
try {
|
|
@@ -455,15 +606,65 @@ class WasmRunner {
|
|
|
455
606
|
return false;
|
|
456
607
|
}
|
|
457
608
|
}
|
|
609
|
+
isModelCompatible(model, input) {
|
|
610
|
+
if (!this.options.compatibilityCheckEnabled) {
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
switch (model.compatibility_status) {
|
|
614
|
+
case types_1.Compatibility.INCOMPATIBLE:
|
|
615
|
+
throw new error_1.default.ModelExecuteError(this.getIncompatibleMessage(model), model.id, input);
|
|
616
|
+
case types_1.Compatibility.PARTIAL:
|
|
617
|
+
logger_1.default.warn({
|
|
618
|
+
TimeStamp: Date.now(),
|
|
619
|
+
EventType: "Runner.Execute.Compatibility.Warning",
|
|
620
|
+
TextMessage: this.getPartiallyCompatibleMessage(model),
|
|
621
|
+
ModelId: model.id,
|
|
622
|
+
});
|
|
623
|
+
return true;
|
|
624
|
+
case types_1.Compatibility.COMPATIBLE:
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
getModelsStats() {
|
|
630
|
+
return this.models.map(model => {
|
|
631
|
+
const stats = Object.assign({}, model.stats);
|
|
632
|
+
Object.keys(stats).forEach(threadId => {
|
|
633
|
+
stats[threadId] = Object.assign({}, stats[threadId]);
|
|
634
|
+
Object.keys(stats[threadId]).forEach(k => {
|
|
635
|
+
if (k.indexOf('_memory') > -1) {
|
|
636
|
+
stats[threadId][`${k}_mb`] = utils.formatMemory(stats[threadId][k]);
|
|
637
|
+
delete stats[threadId][k];
|
|
638
|
+
}
|
|
639
|
+
if (k.indexOf('ready_ts') > -1) {
|
|
640
|
+
stats[threadId].uptime_ms = Date.now() - stats[threadId]['ready_ts'];
|
|
641
|
+
delete stats[threadId][k];
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
return {
|
|
646
|
+
stats: Object.assign(Object.assign({}, stats), { uptime_ms: Math.min(...Object.keys(stats).map((k) => stats[k].uptime_ms)), min_time_ms: model.responseTimeMetrics.min, mean_time_ms: model.responseTimeMetrics.mean, p95_time_ms: model.responseTimeMetrics.p95, p99_time_ms: model.responseTimeMetrics.p99, max_time_ms: model.responseTimeMetrics.max }),
|
|
647
|
+
busy: model.busy,
|
|
648
|
+
size: model.size,
|
|
649
|
+
id: model.id
|
|
650
|
+
};
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
getPartiallyCompatibleMessage(model) {
|
|
654
|
+
return `The Wasm was compiled using ${model.compilerVersion} which is not fully supported by this runner version ${this.safeCompiler}. The service should be able to run but could encounter errors`;
|
|
655
|
+
}
|
|
656
|
+
getIncompatibleMessage(model) {
|
|
657
|
+
return `The Wasm was compiled using ${model.compilerVersion} which is not supported by this runner version ${this.safeCompiler}.`;
|
|
658
|
+
}
|
|
458
659
|
/**
|
|
459
660
|
* Perform calculation. The runner will use request_meta.version_uuid of input argument to locate model
|
|
460
661
|
* @async
|
|
461
662
|
* @param {InputObject} input - Input data for calculation
|
|
462
663
|
* @returns {Promise<ResponseObject>} - Response model data
|
|
463
664
|
*/
|
|
464
|
-
execute(
|
|
465
|
-
|
|
466
|
-
|
|
665
|
+
execute(input_1) {
|
|
666
|
+
return __awaiter(this, arguments, void 0, function* (input, id = undefined, raw = false, cancelToken) {
|
|
667
|
+
var _a, _b, _c;
|
|
467
668
|
let logInput;
|
|
468
669
|
const token = cancelToken ? cancelToken.getToken() : undefined;
|
|
469
670
|
if (utils.isV3Input(input)) {
|
|
@@ -486,7 +687,10 @@ class WasmRunner {
|
|
|
486
687
|
runnerCallId: callid,
|
|
487
688
|
ModelId: id,
|
|
488
689
|
});
|
|
489
|
-
const version_uuid = id ||
|
|
690
|
+
const version_uuid = id ||
|
|
691
|
+
((_b = input === null || input === void 0 ? void 0 : input.request_meta) === null || _b === void 0 ? void 0 : _b.version_uuid) ||
|
|
692
|
+
((_c = input === null || input === void 0 ? void 0 : input.request_meta) === null || _c === void 0 ? void 0 : _c.version_id) ||
|
|
693
|
+
(input === null || input === void 0 ? void 0 : input.version_id);
|
|
490
694
|
if (input) {
|
|
491
695
|
if (raw) {
|
|
492
696
|
if (!input.request_data) {
|
|
@@ -518,15 +722,31 @@ class WasmRunner {
|
|
|
518
722
|
model.busy = model.busy + 1;
|
|
519
723
|
}
|
|
520
724
|
let parsedResult;
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
725
|
+
if (this.isModelCompatible(model, input)) {
|
|
726
|
+
const start = Date.now();
|
|
727
|
+
const res = yield model.worker.execute(input);
|
|
728
|
+
const execTime = Date.now() - start;
|
|
729
|
+
if (res.memoryUsage > model.stats[res.threadId].peak_memory) {
|
|
730
|
+
model.stats[res.threadId].peak_memory = res.memoryUsage;
|
|
731
|
+
}
|
|
732
|
+
model.stats[res.threadId].last_execute_consume_memory = res.memoryUsage;
|
|
733
|
+
model.responseTimeMetrics.record(execTime);
|
|
734
|
+
if (res.error) {
|
|
735
|
+
throw res.error;
|
|
736
|
+
}
|
|
737
|
+
parsedResult = res.payload;
|
|
738
|
+
logger_1.default.debug({
|
|
739
|
+
TimeStamp: Date.now(),
|
|
740
|
+
EventType: "Runner.Execute.Completed",
|
|
741
|
+
executeDuration: Date.now() - start,
|
|
742
|
+
runnerCallId: callid,
|
|
743
|
+
ModelId: id,
|
|
744
|
+
});
|
|
745
|
+
return parsedResult;
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
throw new error_1.default.ModelExecuteError(this.getIncompatibleMessage(model), version_uuid, input);
|
|
749
|
+
}
|
|
530
750
|
}
|
|
531
751
|
catch (err) {
|
|
532
752
|
logger_1.default.error(err);
|
|
@@ -547,6 +767,58 @@ class WasmRunner {
|
|
|
547
767
|
}
|
|
548
768
|
});
|
|
549
769
|
}
|
|
770
|
+
getNeuronCompilerVersion(logFile) {
|
|
771
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
772
|
+
let compilerVersion = undefined;
|
|
773
|
+
const data = fs_1.default.readFileSync(logFile.replace(/"/g, ""), "utf8");
|
|
774
|
+
const modelJsonInfo = JSON.parse(data);
|
|
775
|
+
if (!semver_1.default.valid(modelJsonInfo.CompilerVersion)) {
|
|
776
|
+
throw new error_1.default.CompatibilityJsonError(`The Wasm was compiled using ${modelJsonInfo.CompilerVersion} which is not supported by the compatibility check.`);
|
|
777
|
+
}
|
|
778
|
+
compilerVersion = semver_1.default.coerce(modelJsonInfo.CompilerVersion).version;
|
|
779
|
+
return compilerVersion;
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
checkCompilerVersionCompatibility(modelCompilerVersion) {
|
|
783
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
784
|
+
try {
|
|
785
|
+
const safeCompilerVersion = this.safeCompiler;
|
|
786
|
+
if (modelCompilerVersion) {
|
|
787
|
+
if (semver_1.default.lte(modelCompilerVersion, safeCompilerVersion)) {
|
|
788
|
+
return types_1.Compatibility.COMPATIBLE;
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
return types_1.Compatibility.PARTIAL;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
return types_1.Compatibility.COMPATIBLE;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
catch (err) {
|
|
799
|
+
if (err.code === "ENOENT" || err.message === "File not found") {
|
|
800
|
+
return types_1.Compatibility.COMPATIBLE;
|
|
801
|
+
}
|
|
802
|
+
else if (err instanceof SyntaxError) {
|
|
803
|
+
return types_1.Compatibility.INCOMPATIBLE;
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
throw err;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
getSafeCompilerVersion(runnerVersion) {
|
|
812
|
+
var _a;
|
|
813
|
+
const runnerVersions = (_a = this.options.compatibilityList) === null || _a === void 0 ? void 0 : _a.runner_versions;
|
|
814
|
+
if (!this.options.compatibilityList) {
|
|
815
|
+
throw new error_1.default.CompatibilityJsonError("No runner compiler compatibility list provided");
|
|
816
|
+
}
|
|
817
|
+
if (!runnerVersions.hasOwnProperty(runnerVersion)) {
|
|
818
|
+
throw new error_1.default.CompatibilityJsonError(`No compiler compatibility found for the runner version ${runnerVersion}`);
|
|
819
|
+
}
|
|
820
|
+
return runnerVersions[runnerVersion].safe_compiler;
|
|
821
|
+
}
|
|
550
822
|
}
|
|
551
823
|
exports.WasmRunner = WasmRunner;
|
|
552
824
|
//# sourceMappingURL=node.js.map
|