UNPKG

slavery-js

Version:

A simple clustering app that allows you to scale an application on multiple thread, containers or machines

201 lines 7.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var NodeManager_exports = {}; __export(NodeManager_exports, { default: () => NodeManager_default }); module.exports = __toCommonJS(NodeManager_exports); var import_cluster = __toESM(require("../cluster/index.js"), 1); var import_network = __toESM(require("../network/index.js"), 1); var import_Node = __toESM(require("./Node.js"), 1); var import_utils = require("../utils/index.js"); class NodeManager { constructor(options) { __publicField(this, "name"); __publicField(this, "network"); //private heartBeat: number = 1000; __publicField(this, "nodes", new import_utils.Pool()); __publicField(this, "options"); __publicField(this, "cluster", new import_cluster.default({})); __publicField(this, "stash"); __publicField(this, "setIdle", (NodeId) => this.nodes.enable(NodeId)); __publicField(this, "setBusy", (NodeId) => this.nodes.disable(NodeId)); /* synonims */ __publicField(this, "addNode", this.spawnNodes); __publicField(this, "removeNode", this.killNodes); __publicField(this, "getNumberOfNodes", this.getNodeCount); this.name = options.name; this.options = options; this.network = new import_network.default({ name: this.name + "_node_manager" }); this.network.createServer( this.name + "_node_manager", this.options.host, this.options.port ); this.network.onNodeConnection(this.handleNewNode.bind(this)); this.network.onNodeDisconnect(this.handleNodeDisconnect.bind(this)); this.stash = options.stash || null; } handleNewNode(connection) { (0, import_utils.log)("[Node manager] Got a new connectection from a node"); let node = new import_Node.default(); node.setStashFunctions({ get: async (key) => await this.stash?.get(key), set: async (key, value) => await this.stash?.set(key, value) }); node.setNodeConnection(connection, this.network); node.setStatusChangeCallback(this.handleStatusChange.bind(this)); let id = node.getId(); if (id === void 0) throw new Error("node id is undefined"); this.nodes.add(id, node); this.setIdle(id); } handleNodeDisconnect(connection) { let id = connection.getId(); if (id === void 0) throw new Error("node id is undefined"); this.nodes.remove(id); } handleStatusChange(status, node) { if (!status) throw new Error("status is undefined"); let id = node.getId(); if (id === void 0) throw new Error("node id is undefined"); if (node.isIdle() || node.isError()) this.setIdle(id); else if (node.isBusy()) this.setBusy(id); else throw new Error("invalid node status"); } async getIdle(node_id = "") { if (node_id !== "") { let node2 = this.getNode(node_id); await (0, import_utils.await_interval)(() => node2.isIdle(), 60 * 60 * 60 * 1e3).catch(() => { throw new Error(`timeout of one hour, node ${node_id} is not idle`); }); return node2; } if (this.nodes.isEmpty()) (0, import_utils.log)("[node manager] (WARNING) no nodes found"); await (0, import_utils.await_interval)(() => this.nodes.hasEnabled(), 0).catch(() => { throw new Error("timeout of 10 seconds, no idle node found"); }); let node = this.nodes.pop(); if (node === null) throw new Error("node is null"); return node; } getBusy() { return this.nodes.getDisabled().pop(); } getIdleNodes() { return this.nodes.getEnabledObjects(); } getBusyNodes() { return this.nodes.getDisabledObjects(); } async forEach(callback) { let nodes = this.nodes.toArray(); let promises = nodes.map(async (node) => { if (node.isBusy()) await node.toFinish(); return callback(node); }); return Promise.all(promises); } async registerServices(services) { return this.broadcast( async (node) => await node.registerServices(services) ); } async spawnNodes(name = "", count = 1, metadata = {}) { if (name === "") name = "node_" + this.name; (0, import_utils.log)("[nodeManager][spawnNodes] spawning nodes", name, count); this.cluster.spawn(name, { numberOfSpawns: count, metadata }); } async killNode(nodeId = "") { if (this.nodes.isEmpty()) return false; let node = nodeId === "" ? this.nodes.removeOne() : this.nodes.remove(nodeId); if (node === null || node === void 0) throw new Error("Node sentenced to death could not be found"); await node.exit(); } async killNodes(nodesId = []) { for (let nodeId of nodesId) await this.killNode(nodeId); } getIdleCount() { return this.nodes.getEnabledCount(); } getBusyCount() { return this.nodes.getDisabledCount(); } getNodes() { return this.nodes.toArray(); } nextNode() { return this.nodes.next(); } getNodeCount() { return this.nodes.size(); } getNode(nodeId) { let node = this.nodes.get(nodeId); if (node === null) throw new Error(`[node manager] (ERROR) selected node ${nodeId} not found`); return node; } getListeners() { if (this.network === void 0) throw new Error("network is undefined"); return this.network.getRegisteredListeners(); } async numberOfNodesConnected(count) { let timeout = 1e5; await (0, import_utils.await_interval)(() => this.nodes.size() >= count, timeout).catch(() => { throw new Error(`timeout of ${timeout} seconds, not enough nodes connected`); }); return true; } async exit() { return this.broadcast( async (node) => await node.exit() ); } async broadcast(callback) { let nodes = this.nodes.toArray(); let promises = nodes.map( async (node) => await callback(node) ); return Promise.all(promises); } } var NodeManager_default = NodeManager; //# sourceMappingURL=NodeManager.cjs.map