UNPKG

paraemu

Version:

An working enviroment that provides a simplified interface for developers who want to fully parallelize node execution

171 lines (128 loc) 3.77 kB
(()=>{ "use strict"; const cluster = require( 'cluster' ); const {EventEmitter} = require( 'events' ); const {Helper:{UniqueTimeout}} = include( 'lib' ); const EXPORTED = module.exports = new EventEmitter(); const IS_WIN = (require( 'os' ).platform() === "win32"); const ONLINE_TIMEOUT = UniqueTimeout(); const READY_TIMEOUT = UniqueTimeout(); const EXIT_TIMEOUT = UniqueTimeout(); // Runtime state control const WORKER_STATE_MAP = {}; const WORKER_STATE_LIST = []; // region [ Register task manager apis ] Object.assign(EXPORTED, { killAll:()=>{ }, instantiate:(taskInfo)=>{ const {groupId, taskId, tag, cwd, script, module_paths, args, argv, delay} = taskInfo; WORKER_STATE_LIST.push(WORKER_STATE_MAP[taskId]={ worker: null, ready_notified:false, instantiated:false, available:false, terminated:false, delay }); setTimeout(()=>{ cluster.setupMaster({ cwd, exec:script, execArgv:argv }); const worker = cluster.fork({ paraemu: JSON.stringify({groupId, taskId, tag, args}), NODE_PATH:module_paths.join(IS_WIN ? ';' : ':') }); worker._groupId = groupId; worker._taskId = taskId; worker._tag = tag; WORKER_STATE_MAP[taskId].worker = worker; }, delay); }, sendMessage:(targetId, eventInfo)=>{ for( const {available, worker} of WORKER_STATE_LIST ) { if ( available && ( !targetId||targetId===worker._taskId )) { worker.send(eventInfo); } } } }); // endregion // region [ Handle events from workers ] cluster .on( 'online', (worker)=> { const state = WORKER_STATE_MAP[worker._taskId]; state.instantiated = true; state.available = true; EXPORTED.emit( 'core-state', { type:'worker-started', id:worker._taskId, tag:worker._tag }); ONLINE_TIMEOUT(__CHECK_TASK_ONLINE_STATUS, 0); }) .on( 'exit', (worker, code, signal)=>{ const state = WORKER_STATE_MAP[worker._taskId]; state.available = false; state.terminated = true; EXPORTED.emit( 'core-state', { type: 'worker-terminated', id:worker._taskId, tag:worker._tag, code, signal }); if ( !state.ready_notified ) { state.ready_notified = true; READY_TIMEOUT(__CHECK_READY_STATE, 0); } EXIT_TIMEOUT(__CHECK_TERMINATE_STATE, 0); }) .on( 'disconnected', (worker)=>{ const state = WORKER_STATE_MAP[worker._taskId]; state.available = false; }) .on( 'message', (worker, msg)=>{ if ( Object(msg) !== msg ) { EXPORTED.emit( 'core-data', worker, msg ); return; } switch( msg.type ) { case paraemu.SYSTEM_EVENT.CUSTOM_EVENT: case paraemu.SYSTEM_EVENT.DELIVERY_EVENT: Object.assign(msg, { sender: [worker._taskId, msg.sender].join('-'), target: msg.target ? `${msg.target}` : null }); EXPORTED.emit( 'core-event', msg ); break; case "worker-ready": WORKER_STATE_MAP[worker._taskId].ready_notified = true; READY_TIMEOUT(__CHECK_READY_STATE, 0); break; default: EXPORTED.emit( 'core-data', worker, msg ); break; } }); // endregion function __CHECK_TASK_ONLINE_STATUS() { let all_online = true; for( let {instantiated} of WORKER_STATE_LIST ) { all_online = all_online && instantiated; } if ( all_online ) { EXPORTED.emit( 'tasks-online' ); } } function __CHECK_READY_STATE() { let ready = true; for( let {ready_notified, terminated} of WORKER_STATE_LIST ) { ready = ready && (ready_notified || terminated); } if ( ready ) { EXPORTED.emit( 'tasks-ready' ); } } function __CHECK_TERMINATE_STATE() { let exit = true; for( let {terminated} of WORKER_STATE_LIST ) { exit = exit && terminated; } if ( exit ) { EXPORTED.emit( 'tasks-finished' ); } } })();