UNPKG

slavery-js

Version:

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

127 lines (106 loc) 4.05 kB
import { fork } from 'child_process'; import process from 'node:process'; type SpawnOptions = { numberOfSpawns?: number; allowedToSpawn?: boolean; spawnOnlyFromPrimary?: boolean; metadata?: any; } class Cluster { numberOfProcesses: number; process_timeout: number; crash_on_error: boolean; thisProcess: any; type: string; processes: any[]; allowedToSpawn: boolean; spawnOnlyFromPrimary: boolean; debugging: boolean; constructor(options:any) { this.numberOfProcesses = options.numberOfProcesses || null; this.process_timeout = options.process_timeout || null; this.crash_on_error = options.crash_on_error || false; this.debugging = options.debugging || false; this.type = process.env.type || 'primary'; this.allowedToSpawn = process.env.allowedToSpawn === 'true' || false; this.spawnOnlyFromPrimary = false; this.thisProcess = process; this.processes = []; } public spawn( process_type: string , { numberOfSpawns, allowedToSpawn, spawnOnlyFromPrimary, metadata }: SpawnOptions = {}){ this.log('Spawning new process ' + process_type); this.log(`allowedToSpawn: ${allowedToSpawn}`); this.log('this.amIThePrimaryProcess(): ' + this.amIThePrimaryProcess()); if(numberOfSpawns === undefined) numberOfSpawns = 1; this.spawnOnlyFromPrimary = spawnOnlyFromPrimary || false; // this makes it so that only the primary process can pass the ability to spawn new processes // to another process, otherwise there will be an infinite loop if(this.amIThePrimaryProcess() && allowedToSpawn) allowedToSpawn = true; else allowedToSpawn = false; this.log('final passing on allowedToSpawn ' + allowedToSpawn) // check if the process is allowed to spawn new processes if(this.isProcessAllowedToSpawn() === false) return; let curProcess; for (let i = 0; i < numberOfSpawns; i++){ curProcess = fork( process.argv[1], [], { env: { is_child: 'true', type: process_type, allowedToSpawn: `${allowedToSpawn}`, metadata: JSON.stringify(metadata) } } ) this.processes.push(curProcess); } } private isProcessAllowedToSpawn(){ if(this.spawnOnlyFromPrimary && this.amIChildProcess()) return false; if(this.amIThePrimaryProcess()){ this.log('Primary process is allowed to spawn new processes'); return true; }else this.log('Process is not the primary process'); if(this.allowedToSpawn){ this.log('Process is allowed to spawn new processes'); return true; }else this.log('Process is not allowed to spawn new processes'); return false; } get_this_process() { return this.thisProcess; } get_processes() { return this.processes; } public is(process_type: string) { this.log(`checking if is process ${process_type}`); if(process_type === 'primary') return this.amIThePrimaryProcess(); return process.env.type === process_type; } private amIThePrimaryProcess() { if (this.thisProcess.env.is_child === undefined) return true; if(this.thisProcess.env.is_child === null) return true; if (this.thisProcess.env.is_child === 'false') return true; return false; } public isPrimary() { return this.amIThePrimaryProcess(); } private amIChildProcess() { return process.env.is_child === 'true'; } private log(message: string) { this.debugging && console.log(`[${process.pid}][${this.type}] ${message}`); } public getMetadata() { return process.env.metadata; } } export default Cluster;