@tripod311/leg5
Version:
Zero-dependency concurrent function execution for Node.js using worker threads.
102 lines (101 loc) • 3.45 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const worker_threads_1 = require("worker_threads");
const path_1 = __importDefault(require("path"));
const tools_1 = require("./tools");
class Thread {
constructor(id, abort_timeout, onRelease) {
this.known_tasks = new Set();
this.currentTask = null;
this.id = id;
this.abort_timeout = abort_timeout;
this.onRelease = onRelease;
this.create_worker();
}
shutdown() {
this.worker.postMessage({
command: "terminate"
});
this.timeout = setTimeout(() => {
this.worker.terminate();
}, this.abort_timeout);
}
create_worker() {
this.known_tasks.clear();
const workerPath = path_1.default.join(__dirname, 'executor.js');
this.worker = new worker_threads_1.Worker(workerPath);
this.worker.on("message", this.handle_message.bind(this));
this.worker.on("error", this.handle_error.bind(this));
}
run(task) {
this.currentTask = task;
this.currentTask.assign(this.abort.bind(this));
const transferlist = (0, tools_1.get_transferlist)(task.args);
if (this.known_tasks.has(this.currentTask.name)) {
this.worker.postMessage({
command: "execute",
name: this.currentTask.name,
args: this.currentTask.args,
timeout: this.currentTask.timeout
}, transferlist);
}
else {
this.known_tasks.add(this.currentTask.name);
this.worker.postMessage({
command: "execute",
name: this.currentTask.name,
script: this.currentTask.script,
argsList: this.currentTask.argsList,
args: this.currentTask.args,
timeout: this.currentTask.timeout
}, transferlist);
}
}
abort() {
this.worker.postMessage({
command: "abort"
});
this.timeout = setTimeout(this.forceAbort.bind(this), this.abort_timeout);
}
handle_message(message) {
clearTimeout(this.timeout);
switch (message.command) {
case "finished":
this.currentTask?.finish(message.payload);
this.currentTask = null;
this.onRelease(this.id);
break;
case "failed":
this.currentTask?.fail(message.error.message);
this.currentTask = null;
this.onRelease(this.id);
break;
case "aborted":
this.currentTask?.fail(new Error("Aborted"));
this.currentTask = null;
this.onRelease(this.id);
break;
}
}
handle_error(err) {
this.currentTask?.fail(err);
this.currentTask = null;
this.onRelease(this.id);
this.create_worker();
}
forceAbort() {
this.worker.terminate();
this.currentTask?.fail(new Error("Worker terminated"));
this.create_worker();
}
forget_task(name) {
this.known_tasks.delete(name);
}
get isBusy() {
return this.currentTask !== null;
}
}
exports.default = Thread;