messenger 的 send 和 on 机制能否像 http 通讯一样。 Agent作为服务器 ,Worker 是客户端。
Worker 发送请求 (send) 后等待服务器(Agent)返回结果,Agent 接受数据(on)处理并返回,Worker 的send接收到返回的数据并后续处理。
利用 Agent 唯一的特性,把数据挂载到 Agent 的 app 上作为数据的 Store 来使用。从而达到全局变量的目的。
目前 messenger send 后返回自身,并不等待返回 Agent on 中的 return
Background全局变量总是一个绕不开的话题,因为 eggjs 多进程模型导致各个 Worker 之间共享动态的全局变量变得不可能。也导致一些很简单的事情变得复杂。 例如目前我遇到的一个需求。 需要判断一大堆摄像头是否在线状态,需要请求一个第三方的反代服务器去获得 hls 流。然后判断 hls 流是否能 Get 到来判定在线及延迟。
// app.js 初始化后从第三方平台获取一个非常大的摄像头地址列表
class AppBootHook {
async serverDidReady() {
const bigList = await axios.get('xxx.com/camear/list');
this.app.my = {
currentChecker: 0, // 当前正在检查的数量
maxChecker: 10, // 同时检查的最大数量
concurrency: 2 // 每次检查的并发数量
nextCheckNum: 0 // 下一个需要检测的序号
bigList : bigList , // 检查列表
}
}
}
module.exports = AppBootHook;
// schedule/check.js 创建一个任务计划
module.exports = {
schedule: {
type: 'worker',
interval: “10s”,
immediate: true,
},
async task(ctx) {
const check = ctx.app.my;
try {
if (check.nextCheckNum > check.needCheckArr.length - 1) {
// 如果当前 bigList 中所有摄像头更新完了。更新 bigList
}else{
if (check.currentChecker >= check.maxChecker) return;
// 每次并发出异步的检查请求 更新 currentChecker 的数量
// 检查时间也许很长 1分钟以上等
while (i <= check.concurrency ) {
let id = check.bigList [check.nextCheckNum].id;
check.currentChecker++;
axios.get(`/checkCameraById?id=${id}`).then().catch().finally(() => {
check.currentChecker--;
});
i++;
check.nextCheckNum++;
}
}
} catch (error) {
ctx.app.logger.error(error);
}
},
};
如果只是单线程,以上十分简单。维护挂载在 app.my 上面这个全局变量即可。
多线程的 egg.js 目前看到的 issues 推荐的方案都是把全局变量放到 Redis 或者 数据库 里面去~ 但是我感觉这不是杀鸡用牛刀么~ 只是这么小一个全局变量就需要那么重的外部存储。 而且不管 Redis 还是 数据库,多一个外部的东西就多一份不可控的因素,不太能接受。
我目前采用的办法是通过worker广播消息的方式来维护全局变量。
某个worker全局变量改变后 将最新的全局变量推送给其他 Worker。这样相当于每个worker都存储了一份全局变量。不太划算。不知道有更好的最佳实践没
https://github.com/eggjs/egg/issues/2673
多数人理解应用就是整个程序吧, 这里有歧义。
文档方面是不是增加多进程注意事项的 FAQ。 毕竟本地开发环境是单进程,到生产环境就变成多进程。全局变量 app等不共享这个没注意的话坑挺大的。