/** @type {import('node:cluster').Cluster} */ const cluster = require("cluster"); const os = require("os"); let {randomUUID} = require("crypto"); /** * Use Round Robin algorithm for cluster process load balancer */ // cluster.schedulingPolicy = cluster.SCHED_RR; async function main() { if(cluster.isPrimary == false) { console.log("Slave Process PID:", process.pid); // This process is a worker / slave // Compile source code and run require("./Source/index"); // stay here return; }; // This process is a primary / master console.log("Master Process PID:", process.pid); // Worker process list const master = new Map(); const coreCount = 3 //os.cpus().length; for(let index = 0; index < coreCount; index++) { // Open slave process let worker = await generateFlow(); // Save process with id master.set(worker.id, worker); // Listen process for commands worker.message( // This process want to send payload to sibling process with IPC (workerId, payload) =>{ // Check Target worker if(payload.core) { switch(payload.core) { case "writestat":{ master.get(workerId).setStats(payload) break; } case "readstat":{ master.get(workerId).send({ type: ':stats:', data: [ ...master.entries() ].map(( [, master] ) => { let e = master.getStats(); return { core: master.uuid, ws_writed_bytes:e.ws_writed_bytes, ws_readed_bytes:e.ws_readed_bytes, ws_total_bytes:e.ws_total_bytes, ws_sended_packs:e.ws_sended_packs, ws_recaived_packs:e.ws_recaived_packs, ws_total_packs:e.ws_total_packs, mwse_rooms: e.mwse_rooms, mwse_clients: e.mwse_clients } }) }) break; } } }else if(payload.process) { master.get(payload.process).send({ ...payload, pid: worker.id }) }else for (const [siblingWorkerId,{send}] of master) { // No sending to itself if(workerId !== siblingWorkerId) { // Send command to sibling with IPC send({ ...payload, pid: worker.id }) } } } ) } } async function generateFlow() { // Mirror this process with for (low-level os multitasking) const worker = cluster.fork(); // Wait process is online await new Promise(ok => { worker.addListener("online",()=> { ok() }) }); // Get process pid on the os let id = worker.process.pid; let stats = {}; // Simplification wrapping send and get events with IPC's event functions return { id, uuid: randomUUID(), send: message => worker.send(message), message: (callback) => worker.addListener("message", e => callback(id,e)), getStats: () => stats, setStats: e => Object.assign(stats, e) } } // Run immediately process.nextTick(main);