expressmultithread
Version:
Fast, light-weight and low dependency [Express.js](https://www.npmjs.com/package/express) multithreaded router.
175 lines • 6.09 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Instance = void 0;
const worker_threads_1 = require("worker_threads");
const types_1 = require("../types");
const config_1 = __importDefault(require("../config"));
const strings_1 = require("../constants/strings");
const postMessage_1 = require("../functions/utils/postMessage");
const compareArray_1 = require("../functions/utils/compareArray");
const strings_2 = require("../constants/strings");
class Parent {
constructor(threadCount = config_1.default.threadCount) {
this.childs = [];
this._sources = [];
this.inc = 0;
this.indexRobin = 0;
for (let i = 0; i < threadCount; i++) {
this.newChild();
}
}
;
newChild() {
this.inc++;
config_1.default.verbose && console.info("Starting thread id :", this.inc);
const child = new worker_threads_1.Worker(__dirname + strings_1.slash + strings_1.childFile, {
workerData: {
id: this.inc
}
});
child.on(strings_1.message, (data) => {
const parsed = JSON.parse(data);
const z = this.childs.findIndex(child => child.id === parsed.id);
if (z === -1)
throw new Error(strings_1.childNotFound);
switch (parsed.cmd) {
case types_1.ChildCmd.ready: {
this.childs[z].ready = true;
break;
}
case types_1.ChildCmd.response: {
const task = this.childs[z].tasks.get(parsed.tid);
task && task.res[parsed.call](...parsed.args);
break;
}
case types_1.ChildCmd.next: {
const task = this.childs[z].tasks.get(parsed.tid);
if (task) {
parsed.arg !== undefined && task.next(parsed.arg);
this.childs[z].tasks.delete(parsed.tid);
}
break;
}
default:
throw new Error(`Unknown command : '${parsed.cmd}'`);
}
});
child.on(strings_1.error, (e) => {
console.error(e);
if (config_1.default.restartThreads)
return this.newChild();
else
throw e;
});
config_1.default.debug && console.debug("Creating child id ", this.inc, " :\nsources :", this._sources);
(0, postMessage_1.postChild)(child, {
cmd: types_1.ParentCmd.setSource,
source: this._sources
});
this.childs.push({
id: this.inc,
instance: child,
tasks: new Map(),
ready: false
});
}
;
dispatchTask(task) {
let i = 0;
switch (config_1.default.dispatcher) {
case strings_2.DispatcherType.ROUND_ROBIN: {
i = (this.indexRobin++) % this.childs.length;
break;
}
case strings_2.DispatcherType.LEAST_CONNECTION: {
const occupation = this.childs.map((c) => c.ready ? c.tasks.size : Infinity);
const min = Math.min(...occupation);
i = occupation.indexOf(min);
break;
}
default: {
throw new Error(`Unknown dispatcher type: '${config_1.default.dispatcher}'`);
}
}
this.childs[i].tasks.set(task.id, task);
const cb = () => {
task.res.removeListener("close", cb);
task.res.removeListener("finish", cb);
this.childs[i].tasks.delete(task.id);
};
task.res.addListener("close", cb);
task.res.addListener("finish", cb);
(0, postMessage_1.postChild)(this.childs[i].instance, {
cmd: types_1.ParentCmd.request,
req: config_1.default.cleanRequest(task.req),
id: task.id
});
}
;
addSource(source) {
for (let i = 0; i < source.length; i++) {
this._sources.push({
path: source[i],
type: types_1.SourceType.CONTROLLER
});
}
this.postChilds(types_1.ParentCmd.setSource, {
source: this._sources
});
}
;
addMiddleware(path, opts) {
this._sources.push({
path,
type: types_1.SourceType.GLOBAL_MIDDLEWARE,
args: opts
});
this.postChilds(types_1.ParentCmd.setSource, {
source: this._sources
});
}
;
removeMiddleware(opts, path) {
if (!path) {
this._sources = this._sources.filter((source) => source.type !== types_1.SourceType.GLOBAL_MIDDLEWARE);
}
else {
for (let i = 0; i < this._sources.length; i++) {
if (this._sources[i].type !== types_1.SourceType.GLOBAL_MIDDLEWARE)
continue;
if (this._sources[i].path === path && (0, compareArray_1.compareArray)(this._sources[i].args ?? [], opts))
this._sources.splice(i, 1);
}
}
this.postChilds(types_1.ParentCmd.setSource, {
source: this._sources
});
}
;
close() {
for (let i = 0; i < this.childs.length; i++) {
this.childs[i].instance.terminate();
}
}
;
postChilds(cmd, data) {
data.cmd = cmd;
for (let i = 0; i < this.childs.length; i++) {
(0, postMessage_1.postChild)(this.childs[i].instance, data);
}
}
;
get _sourcesList() {
return this._sources;
}
;
get _inc() {
return this.inc;
}
}
exports.Instance = worker_threads_1.isMainThread ? new Parent() : null;
exports.default = exports.Instance;
//# sourceMappingURL=Parent.js.map