关于egg.js 的生命周期,有在egg-sequelize测试数据库链接前的方法吗?
发布于 6 年前 作者 thomas0836 4108 次浏览 来自 问答

问题的起因是,在阿里云的ECS上尝试部署Egg的项目的,但是一直报

 ERROR 449 nodejs.SequelizeAccessDeniedError: Access denied for user 'root'@'localhost' (using password: YES)
[egg-scripts]     at Utils.Promise.tap.then.catch.err (/home/egg/hc_user/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:141:19)
[egg-scripts]     at tryCatcher (/home/egg/hc_user/node_modules/bluebird/js/release/util.js:16:23)
[egg-scripts]     at Promise._settlePromiseFromHandler (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:512:31)
[egg-scripts]     at Promise._settlePromise (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:569:18)
[egg-scripts]     at Promise._settlePromise0 (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:614:10)
[egg-scripts]     at Promise._settlePromises (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:690:18)
[egg-scripts]     at _drainQueueStep (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:138:12)
[egg-scripts]     at _drainQueue (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:131:9)
[egg-scripts]     at Async._drainQueues (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:147:5)
[egg-scripts]     at Immediate.Async.drainQueues [as _onImmediate] (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:17:14)
[egg-scripts]     at runCallback (timers.js:693:18)
[egg-scripts]     at tryOnImmediate (timers.js:664:5)
[egg-scripts]     at processImmediate (timers.js:646:5)
[egg-scripts] name: "SequelizeAccessDeniedError"
[egg-scripts] parent: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
[egg-scripts] original: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}

数据库是阿里云的RDS Mysql,已开白名单,在ECS上尝试过ping RDS 的链接,可以ping通。 尝试过在RDS多加一个testuser的用户,配置上testuser的账号密码后,还是报一样的错误。如果 user 改变了 ‘root’@‘localhost’ 这里应该会变成’testuser’@‘localhost’ 的吧? config.prod.js 的配置如下

'use strict';
module.exports = () => {
  const config = exports = {};
  // change to your own sequelize configurations
  config.sequelize = {
    dialect: 'mysql',
    port: 3306,
    hostname: '2123123123123123.mysql.rds.aliyuncs.com',
    database: 'test',
    user: 'testuser',
    password: '12123123123',
    define: {
      underscored: false,
    },
  };
  return config;
};

config.default.js 中没有sequelize 的配置,config.local.js 中的sequelize 配置也改成和config.prod.js 问题一样。 数据库的账号密码也在dms-rds.aliyun.com/main.do 上试过登陆,是没有问题的。 因为这个ECS 是用来测试的,所以内部也安装了一个mysql。 目前不清楚到底项目是按那个配置在运行,链接的mysql是那个,用那个账号密码来链接。 ECS上部署的项目 是用

egg-scripts start --daemon

来运行的,同样也有试过

EGG_SERVER_ENV=prod  egg-scripts start --daemon
// 或者 
export NODE_ENV=production  &&  egg-scripts start --daemon

问题一样。

为了了解项目的目前情况,加了一个app.js 的文件

'use strict';
class AppBootHook {
  constructor(app) {
    console.log('\x1B[31m%s\x1b[0m:', `constructor... app: ${JSON.stringify(app)}`);
    app.beforeStart(() => {
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor beforeStart app.config.env: ${app.config.env}, process.env.NODE_ENV: ${process.env.NODE_ENV}`);
    });
    app.ready((...a) => {
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor ready...  a: ${JSON.stringify(a)}`);
    });

    app.beforeClose((...a) => {
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor beforeClose...  a: ${JSON.stringify(a)}`);
    });

    app.once('server', server => {
      // websocket
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor once('server')...  server: ${JSON.stringify(server)}`);
    });
    app.on('error', (err, ctx) => {
      // report error
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor on('error')...  ctx: ${JSON.stringify(ctx)} , err: ${JSON.stringify(err)}`);
    });
    app.on('request', ctx => {
      // log receive request
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor on('request')...  ctx: ${JSON.stringify(ctx)}`);
    });
    app.on('response', ctx => {
      // ctx.starttime is set by framework
      const used = Date.now() - ctx.starttime;
      app.logger.info('\x1B[31m%s\x1b[0m:', `constructor on('response')...  ctx: ${JSON.stringify(ctx)}, used: ${used}`);
      // log total cost
    });

  }

  async beforeStart(...a) {
    console.log('\x1B[31m%s\x1b[0m:', `beforeStart...  a: ${JSON.stringify(a)}`);
  }

  async ready(...a) {
    console.log('\x1B[31m%s\x1b[0m:', `ready...  a: ${JSON.stringify(a)}`);
  }

  configDidLoad(...a) {
    // Config,plugin files have did load.
    console.log('\x1B[31m%s\x1b[0m:', `configDidLoad...  a: ${JSON.stringify(a)}`);
  }

  async didLoad(...a) {
    // All files have did load, start plugin here.
    console.log('\x1B[31m%s\x1b[0m:', `didLoad...  a: ${JSON.stringify(a)}`);
  }

  async willReady(...a) {
    // All plugins have started, can do some thing before app ready
    console.log('\x1B[31m%s\x1b[0m:', `willReady...  a: ${JSON.stringify(a)}`);
  }

  async didReady(...a) {
    // Worker is ready, can do some things
    // don't need to block the app boot.
    console.log('\x1B[31m%s\x1b[0m:', `didReady...  a: ${JSON.stringify(a)}`);
  }

  async serverDidReady(...a) {
    // Server is listening.
    console.log('\x1B[31m%s\x1b[0m:', `serverDidReady...  a: ${JSON.stringify(a)}`);
  }

  async beforeClose(...a) {
    // Do some thing before app close.
    console.log('\x1B[31m%s\x1b[0m:', `beforeClose...  a: ${JSON.stringify(a)}`);
  }
}

module.exports = AppBootHook;

在本地 egg-bin dev 的时候输出的是 屏幕快照 2018-10-12 上午10.34.45.png

在ECS上 运行 egg-scripts start --daemon 的时候

> egg-scripts start --daemon

[egg-scripts] Starting egg application at /home/egg/hc_user
[egg-scripts] Run node /home/egg/hc_user/node_modules/egg-scripts/lib/start-cluster {"title":"egg-server-hc_user","framework":"/home/egg/hc_user/node_modules/egg","baseDir":"/home/egg/hc_user"} --title=egg-server-hc_user
[egg-scripts] Save log file to /root/logs
[egg-scripts] Wait Start: 1...
[egg-scripts] Wait Start: 2...
[egg-scripts] tail -n 100 /root/logs/master-stderr.log
[egg-scripts] Got error when startup: 
[egg-scripts] 2018-10-12 10:38:39,134 ERROR 449 nodejs.SequelizeAccessDeniedError: Access denied for user 'root'@'localhost' (using password: YES)
[egg-scripts]     at Utils.Promise.tap.then.catch.err (/home/egg/hc_user/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:141:19)
[egg-scripts]     at tryCatcher (/home/egg/hc_user/node_modules/bluebird/js/release/util.js:16:23)
[egg-scripts]     at Promise._settlePromiseFromHandler (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:512:31)
[egg-scripts]     at Promise._settlePromise (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:569:18)
[egg-scripts]     at Promise._settlePromise0 (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:614:10)
[egg-scripts]     at Promise._settlePromises (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:690:18)
[egg-scripts]     at _drainQueueStep (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:138:12)
[egg-scripts]     at _drainQueue (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:131:9)
[egg-scripts]     at Async._drainQueues (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:147:5)
[egg-scripts]     at Immediate.Async.drainQueues [as _onImmediate] (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:17:14)
[egg-scripts]     at runCallback (timers.js:693:18)
[egg-scripts]     at tryOnImmediate (timers.js:664:5)
[egg-scripts]     at processImmediate (timers.js:646:5)
[egg-scripts] name: "SequelizeAccessDeniedError"
[egg-scripts] parent: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
[egg-scripts] original: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}

还没有加载到app.js 的感觉。 请问,要怎样去解决这个问题? egg.js 的生命周期方法,有在egg-sequelize测试数据库链接前的方法吗?

19 回复

你本地远程连接你的mysql可以成功吗?

目前不清楚到底项目是按那个配置在运行,链接的mysql是那个,用那个账号密码来链接。

用 egg-scripts 启动的话是 prod,不用加环境变量。

你可以看下启动后的 run/application_config.json 里面的配置,这个是 dump 出来的最终合并配置(仅查看)

@wang-weifeng 其他框架的项目可以

@atian25 弱弱地问,如果在启动时都会把这些变量都输出一下,会不会更好?我们菜鸟的项目基本都会这样做,不知道大神们是怎么看。

@thomas0836 都输出到 run/application_config.json 了啊

@atian25 请问,有一些更详细的关于部署的推荐文档吗?基本上都不怎么看到有类似的手把手教程,对于初级运维来说,很痛苦呢。 之前的项目基本都是上传到git,然后服务器装个git,来下载然后安装依赖。再pm2用export NODE_ENV=development 来运行。 看了eggjs后才知道原来是要本地打包,整个连依赖一起上传到服务器。但是按照eggjs上的教程,有几个小问题。例如在本地开发时.gitgnore 上配置的一些不需要上传的内容,都全部在压缩包里面了吧?难道是需要开一个新的目录在本机用git再重新下载,再按照发布的来安装依赖,再压缩打包,再上传? 想请教一下其他的专业团队是如何部署的。希望有大神可以分享一下

谢谢 @atian25, 查了 服务器上 run/application_config.json

"sequelize": {
      "dialect": "mysql",
      "database": "test",
      "host": "localhost",
      "port": 3306,
      "username": "root",
      "password": "<String len: 12>",
      "hostname": "127.0.0.1",
      "define": {
        "underscored": false
      }
    },

想了解一下,这个文件是在本地 npm install --production 的时候生成的,还是说在ECS 上解压后 运行 egg-scripts start --daemon 再生成?

@thomas0836 一般做法是:

ci 机器上, git clone,安装依赖,打包,上传。

=.= run 的时候生成的

egg-bin 启动是 dev egg-script 启动是 prod 没毛病啊。看来还是文档读少了。

@MiYogurt 谢谢,刚刚测试也测试到了,把ECS上的run文件夹删除了,然后再运行

EGG_SERVER_ENV=prod  egg-scripts start --daemon
// 或者 
export NODE_ENV=production  &&  egg-scripts start --daemon

发现是会自动生成 run/application_config.json 但是 情况还是一样。明显是development时的数据库配置,而不是发布的配置。

我也再检查过这个 数据库名在整个项目中只出现过3次,一次在config.local.js , 一次在 /database/config.json ,最后一次是在/run/application_config.json /database/config.json 中也确认是在development 内,而不是在 production 内。

请问 我这里的运行命令是不是错了?@atian25

不需要加任何变量,就是 egg-scripts start 肯定是会加载 config.prod.jsconfig.default.js /run/application_config.json 我在上面已经说了,它就是启动期 dump 的一个供排查用的日志,代表最终配置合并的结果。

/database/config.json 这玩意不知道哪来的,检查下你自己的代码吧。

另外,建议再去看看 配置 那一章文档。

谢谢 @atian25 建了一个最少复现仓库了 https://github.com/ThomasLiu/egg_RESTfulAPI_mysql 希望可以获得你们的优化建议。

至于 /database/config.json 是 https://eggjs.org/zh-cn/tutorials/sequelize.html 内提到的Migrations 用的。

@thomas0836 Good Job~

现在的问题是什么?

@atian25 就是按照部署那章在ECS 上部署的时候,config.prod.js 的数据库配置不能正常的合并到 /run/application_config.json 里面,使用的命令有

egg-scripts start
// 或者 
EGG_SERVER_ENV=prod  egg-scripts start --daemon
// 或者 
export NODE_ENV=production  &&  egg-scripts start --daemon

你本地同样命令呢?

@atian25 我在新开出来的那个仓库刚才再试了一下,直接用 egg-scripts start 运行,可以成功合并到 /run/application_config.json 里面了,但是还是提示

Got error when startup: 
[egg-scripts] 2018-10-13 17:31:21,183 ERROR 11148 nodejs.SequelizeAccessDeniedError: Access denied for user 'root'@'localhost' (using password: YES)
[egg-scripts]     at Utils.Promise.tap.then.catch.err (/home/egg/egg_RESTfulAPI_mysql/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:141:19)
[egg-scripts]     at tryCatcher (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/util.js:16:23)
[egg-scripts]     at Promise._settlePromiseFromHandler (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:512:31)
[egg-scripts]     at Promise._settlePromise (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:569:18)
[egg-scripts]     at Promise._settlePromise0 (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:614:10)
[egg-scripts]     at Promise._settlePromises (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:690:18)
[egg-scripts]     at _drainQueueStep (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:138:12)
[egg-scripts]     at _drainQueue (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:131:9)
[egg-scripts]     at Async._drainQueues (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:147:5)
[egg-scripts]     at Immediate.Async.drainQueues [as _onImmediate] (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:17:14)
[egg-scripts]     at runCallback (timers.js:693:18)
[egg-scripts]     at tryOnImmediate (timers.js:664:5)
[egg-scripts]     at processImmediate (timers.js:646:5)
[egg-scripts] name: "SequelizeAccessDeniedError"
[egg-scripts] parent: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
[egg-scripts] original: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}

我再去看看那个数据库配置和数据库那边的账号密码,再仔细过一次吧

@atian25 @wang-weifeng @MiYogurt 谢谢,问题已解决,原因是config.prod.js 文件内由于sequelize 的版本问题。 以前用的hostname 换成了host, user 换成了 username。在本地开发的时候这两个参数也是写错的,因为刚好也是用root和127.0.0.1,所以问题没有暴露出来。

回到顶部