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 = 1 //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); |