关于egg中加载器(Loader)问题
发布于 5 年前 作者 ddzyan 7968 次浏览 来自 问答

现在遇到一个需求,需要将数据库的配置文件放在 apollo 中进行管理,所以写了一个本地插件 egg-apollo 项目中进行异步获取配置,预计的想法是:

  1. 先执行 egg-apollo 插件,异步获取数据库配置
  2. 更新 this.config.sequelize 对象
  3. 初始 egg-sequelize 插件

但是现在无论把 egg-apollo 获取配置的方法写到loader哪个生命周期去,都无法阻止 egg-sequelize 比 egg-apollo 早执行,有啥有效的方法吗?

22 回复

image.png 按照官方文档的执行顺序来说,我这样配置应该没得问题吧,先更新this.config,再初始化 egg-sequelize

试试 egg-apollo 在 agent 里面获取配置,写到文件。然后 app 里面读取文件塞到 config

这是我 egg-apollo 中 agent.js 中的代码

 assert(agent.config.apolloDdz, 'apolloDdz config is required');
    const config = await apollo.remoteConfigServiceSikpCache(agent.config.apolloDdz);
    // this.coreLogger.info(`apollo 初始化完成${new Date()}`, bundle);

    const configFilePath = __dirname + '/config/config.default.js';

    if (fs.existsSync(configFilePath)) {
      fs.unlinkSync(configFilePath);
    }

    let configText = "'use strict';\n";
    configText = configText + 'module.exports = () => {\n return';
    configText = configText + JSON.stringify(config);
    configText = configText + '};';
    fs.appendFileSync(configFilePath, configText);

现在遇到的问题是,项目使用 egg-bin debug 启动,如果把配置信息写到 config.default.js 中,会检查到代码有变化然后进行重启,然后继续获取配置文件,写到 config.default.js 中进入死循环

你应该写到 xx.json,然后 config 里面 require 这个文件。

然后 xx.json 这个配置到 egg-development 的 ignore 里面

感谢,已经实现

@atian25 现在我将获取配置的代码写在 agent.js 中,代码内容如下。但是在测试中,config中的 require json文件的代码运行的时间比 agent.js 中生成json文件早,导致无法加载报错,请问是我哪里操作错误了吗?

//agent.js
'use strict';
const assert = require('assert');
const fs = require('fs');
const apollo = require('./lib/apollo');

module.exports = async agent => {
  agent.beforeStart(async () => {
    assert(agent.config.apolloDdz, 'apolloDdz config is required');
    const config = await apollo.remoteConfigServiceSikpCache(agent.config.apolloDdz);


    const configFilePath = __dirname + '/config/apollo-config.json';

    if (fs.existsSync(configFilePath)) {
      fs.unlinkSync(configFilePath);
    }
    const configStr = JSON.stringify(config);
    fs.appendFileSync(configFilePath, configStr);
    agent.coreLogger.info(`apollo 初始化完成${new Date()}`);
  });
};
//config.default.js
'use strict';
module.exports = () => {
  const config = require('./apollo-config.json');
  return config;
};

  • mm.app 是把 agent 和 app 模拟在一个进程里面来加速测试的,可能这里的时序有问题。
  • 可以实现新的生命周期的写法,beforeStart 已经是不推荐的了
  • 如果还不行,就用 mm.cluster 的测试方式

@atian25 我上面的配置加载方式,现在项目启动就会直接报错,Error: Cannot find module ‘./apollo-config.json’。在 agent.js 先获取配置在写到json文件中去,然后在插件的 config.default.js 中进行加载,这个顺序是不是有问题呢?因为代码启动是不按照这个顺序执行的

现在解决办法是将读取 json 配置的方法,写到 config.prod.js 或者 config.local.js 中,不允许写在 config.default.js中

@ddzyan 可以带最小可复现仓库提交 issue 我们看看

@atian25 这是代码仓库,稍后我会添加到issue中 https://github.com/ddzyan/apollo-loader-test

image.png 按照egg-loader的文档说明,config的加载是在agent.js之前,是不是说明 egg 无法进行动态获取配置,来配置数据库插件呢

顶顶顶,大佬们有啥解决方案吗?现在的想法是修改启动命令,类似如下:

node getApollo.js && egg-bin debug

node getApollo.js 负责第一次获取apollo配置,并且写入json文件中,再在 config.*.js 中读取json配置添加配置,解决config提早加载的问题

@ddzyan 实在不行你把egg-sequelize 复制一遍改成新的hook写法,推迟到更后的生命周期再加载数据库

@AnzerWall 这样的话我觉得我上面的改动方法会好点。 只是我原本的目的是做一个 egg-apollo 插件,不应该涉及到其他插件的修改。主要想了解下egg是否支持异步获取配置,并且在插件启动前进行更新。

这是我提交的issue https://github.com/eggjs/egg/issues/4113

这个问题是不是无解了呢?或者说EGG暂时没考虑使用apollo获取动态配置(例如数据库连接配置)呢

@ddzyan 我的实现方式是不用egg-script启动,使用egg-cluster自定义启动脚本,然后在启动脚本中异步获取配置,写到json文件中,config中require这个json文件,我看过源码,agent的加载顺序与app的是一样的,所以,config肯定是在你异步获取配置之前就已经加载了,egg-sequellize在agent中就会加载,所以在agent里面异步获取是不行的。脚本这种启动方式也是官方提供的方式,所以不用担心,具体查看官方文档,我用的方式,已经在生产环境应用了,完全莫得问题。看一下吧解决方式

@ddzyan 如果要使用 apollo 的热更新的话,就是无解的,至少现在是

因为热更新的时候可能需要重启 sequelize、redis… 这种骚操作在生产就是坟头蹦迪 233

如果只是将 apollo 作为一个存配置的地方,启动之前直接跑个脚本去拉一下就行

@xiedacon 还是有临时解的,在 agent 里面 appollo 拉配置,然后写文件,在 worker 这边 require

@atian25 写文件当然是可以的,我说的是 “热更新”,指程序跑到一半突然更新

我看他那个插件里面是这么写的,,

@xiedacon 那需要对用到的插件都要做处理,支持重新建立连接。

回到顶部