nodeJS同时运行多个子进程


在游戏项目开发中,经常会遇到有大厅内含多个子程序的模式,这时候使用nodeJs做服务端时会涉及到对多个子进程的管理和框架问题,结合以往的实际开发经验,对这种模式的服务端设计做个简单的总结。

1.  核心模块

child_process和fs

child_process模块主要用于在主进程运行的时候衍生出独立于主进程的异步子进程。

fs模块主要用于在主进程内读取需要的配置文件

2.  实现方式

首先需要一个配置文件来配置子进程的信息,一般使用json文件,例如:

[

{

“name”:”game1”,

“path”:”Game/game1”,

“port”:1100,

“status”:0,

“des”:”子进程一”

},

{

“name”:”game2”,

“path”:”Game/game2”,

“port”:1200,

“status”:0,

“des”:”子进程二”

},

{

“name”:”game3”,

“path”:”Game/game3”,

“port”:1300,

“status”:0,

“des”:”子进程三”

}

]



这样一个json文件自定义了每个需要运行的子进程的名字,运行的js文件的路径,端口,服务端的状态,描述这些信息。

下面函数示例如可在运行的主进程的用这样一个方法去获取配置文件信息

/**
 * 获取配置文件
 * @param {string}manifestUrl 配置json路径
 * @returns {Promise<Array<any>>}
 */
private async getManifest(manifestUrl:string):Promise<Array<any>> {
        let manifest = [];
        let fileName = await path.resolve(__dirname,manifestUrl);
        let exists = await fs.existsSync(fileName);
        if (exists) {
            let manifestStr = awaitfs.readFileSync(fileName);
            if (manifestStr) {
                try {
                     manifest = await JSON.parse(manifestStr.toString("utf-8"));
                } catch (e) {
                    console.error(config.manifestFileName+ "错误!", e.message);
                }
            }
        } else {
            console.error(config.manifestFileName+ "不存在!");
            process.exit(0);
        }
    return manifest;
}


下面函数示例可运行一个单个的进程一个item就是获取到的配置对象的一个节点元素

/**
 * 运行一个实例
 * @param item
 * @param restart
 */
private async runInstance(item: any, restart = 0) {
    let instanceObj = {
        name: item.name,
        desc: item.desc,
        path: item.path,
        port: item.port,
        status: item.status,
        cpu: "0%",
        memory: "0%",
        restart: restart,
        instance: null,
        version: "0"
    };
    if (!instanceObj["timer"]){
        instanceObj["timer"] = setTimeout(()=> {
            if (instanceObj.status== 0) {
                instanceObj.restart = 0;
                instanceObj["timer"]= null;
                delete instanceObj["timer"];
            }
        }, 500);
    }
    if (item.status != 1) {
        let arg = {
            port: item.port,
            serverName: item.name,
        };
        // 日志路径
        let logPath = "";
        let pathArr = item.path.split("/");
        for (let i = 0; i< pathArr.length - 1; i++) logPath += pathArr[i] + "/";
        instanceObj["logPath"]= logPath + "Logs.txt";
        // fork模式运行
        instanceObj.instance = cps.fork(path.resolve(__dirname,"./controller/" + item.path), [encodeURIComponent(JSON.stringify(arg))],{silent: true});
        // 监听输出事件
        instanceObj.instance.stdout.on("data",async (data: Buffer) => {
            // todo 写入流到 log.txt
        });
        // 错误事件
        instanceObj.instance.stderr.on("data",async (data: Buffer) => {
            // todo 重启 写入错误日志等等
        });
        // 接收消息
        instanceObj.instance.on("message",async (msg: any) => {
            if (msg &&msg.method && this[msg.method]) {
                instanceObj &&instanceObj.instance && instanceObj.instance.send({
                    method: msg.method,
                    data: await this[msg.method](...msg.arg)
                })
            }
        });
    }
}

这种模式管理每个进程的内存,cpu 版本信息都很方便,所有子进程可以通过继承方式继承一个类,通过process.argv[2]进行端口,版本等信息的管理。


 

 


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值