UNPKG

slavery-js

Version:

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

172 lines 5.55 kB
import { __publicField } from "../chunk-V6TY7KAL.js"; import Cluster from "../cluster/index.js"; import Network from "../network/index.js"; import Node from "./Node.js"; import { Pool, await_interval, log } from "../utils/index.js"; class NodeManager { constructor(options) { __publicField(this, "name"); __publicField(this, "network"); //private heartBeat: number = 1000; __publicField(this, "nodes", new Pool()); __publicField(this, "options"); __publicField(this, "cluster", new Cluster({})); __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 Network({ 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) { log("[Node manager] Got a new connectection from a node"); let node = new Node(); 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 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()) log("[node manager] (WARNING) no nodes found"); await 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; 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 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; export { NodeManager_default as default }; //# sourceMappingURL=NodeManager.js.map