127 lines
4.1 KiB
JavaScript
127 lines
4.1 KiB
JavaScript
/** @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); |