升级 Node.js 版本遇到 co 和 pm2 问题解析

2018-10-2511:11:06WEB前端开发Comments3,824 views字数 2365阅读模式

nodejs 4.x 的项目, 需要升级到6.9.5(当时最新的稳定版本)以改善性能和可靠性.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

业务中使用到了co, 进程使用 pm2 管理.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

升级nodejs版本

确保构建脚本能够使用nvm安装nodejs 6.9.5, 本地运行基本ok文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

从 co 的问题开始

UnhandledPromiseRejectionWarning: Cannot read property 'done' of undefined
复制代码

服务启动时即产生上述报警信息, 服务不可用, 通过搜索发现是存在某个promise最终reject了, 但是没有catch. 知道直接原因是这样, 但没啥帮助, 我上哪去找这种特点的代码.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

考虑断点调试文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

process.on('unhandledRejection', function(reason, p){
  console.log('=======================');
  console.log(reason);
  console.log(p);
});
复制代码

上述代码加到服务开始启动, 本地调试启动, 发现一切正常 -_-b文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

不复现问题, 回顾整个问题, 目测可能是测试环境问题, 先看看nodejs版本吧文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

console.log(process.versions)
复制代码

竟然nodejs版本还是旧版本文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

pm2 的问题

能决定nodejs版本的途径就只有进程启动了, 哪问题就落到 pm2 这边了, 去检查pm2的进程配置文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

> pm2 show myapp_name
│ interpreter       │ node
│ interpreter args  │ --harmony
....
│ exec mode         │ cluster_mode
│ node.js version   │ 4.4.2
复制代码

果然版本有问题, 考虑pm2这种进程管理模型, daemon进程启动后, 再逐个启动worker进程, 而 exec mode: cluster_mode 意味着它使用了nodejs的cluster模块来启动子进程.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

进一步的, cluster启动子进程是用fork()启动的, 子进程的版本和父进程版本应该是一致的. 大概率是这个原因.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

简单重启daemon进程的办法是 pm2 kill 干掉daemon和所有worker进程后, 重新pm2 start. 一番折腾后的结论:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

  1. daemon进程更新, 除了 pm2 kill && pm2 ping可以重启daemon外, 还可以 pm2 update 它还会使用当前版本pm2
  2. 想要让app生效还是建议重新添加app, pm2 delete app.json && pm2 start app.json

测试环境 重启了pm2 daemon进程后, 启动仍旧是前文遇到的报警, 但 node.js version 输出是符合预期了.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

虽然没解决问题, 但升级版本是必须的. 继续看看, 收集线索文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

回到 co 的问题

现在nodejs版本一致, 但是测试环境报警, 本地不复现, 可能还是环境问题, 继续看进程配置, 发现 interpreter args: --harmony文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

这个是旧版本nodejs为了兼容新的特性加的开关, 考虑到错误堆栈是从co中过来的, 查看co的文档文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

升级 Node.js 版本遇到 co 和 pm2 问题解析

按理v4+之后就不需要加这个开关, 暂且不关心为什么加这个开关, 目前能找到的差异就是这个地方, 先本地加上这个开关运行看看文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

结果复现相同的报警, 本地和测试环境现象一致文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

接下来就好办了, 到app.json中删除这段配置, pm2 delete app.json && pm2 start app.json 重新启动app, 问题解决.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

总结

  1. pm2 cluster_mode 升级nodejs时需要同步更新daemon进程
  2. worker进程的配置也需要手工更新
  3. nodejs不会保证部分实验性开关的兼容性

实际遇到的环境问题可能都是混杂多个关键原因, 必须得解决所有的原因才能正常工作.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

错误才是常态, 正确是一连串的偶然组合在一起文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

遗留疑问: --harmony 怎么加上去的

了解cluster的同学应该知道 fork() 只有一个参数 环境变量, 那就有些奇怪的地方了.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

一种可能是 pm2 daemon 启动时加上去的, 但也不合逻辑, daemon可能会管理多个项目, 有的是cluster, 有的不是.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

只是猜测显然不行, 看源码吧文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

God.nodeApp = function nodeApp(env_copy, cb){
  var clu = null;
 
  console.log('Starting execution sequence in -cluster mode- for app name:%s id:%s',
              env_copy.name,
              env_copy.pm_id);
 
  if (env_copy.node_args && Array.isArray(env_copy.node_args)) {
    // 注意下面这行
    cluster.settings.execArgv = env_copy.node_args;
  }
 
  env_copy._pm2_version = pkg.version;
 
  try {
    // node.js cluster clients can not receive deep-level objects or arrays in the forked process, e.g.:
    // { "args": ["foo", "bar"], "env": { "foo1": "bar1" }} will be parsed to
    // { "args": "foo, bar", "env": "[object Object]"}
    // So we passing a stringified JSON here.
    clu = cluster.fork({pm2_env: JSON.stringify(env_copy)});
  } catch(e) {
    God.logAndGenerateError(e);
    return cb(e);
  }
复制代码

重新翻看 cluster 的文档, 发现确实存在 cluster.settings文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

升级 Node.js 版本遇到 co 和 pm2 问题解析

作者:netwjx曹宇
来源:掘金文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7251.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/7251.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定