内容简介:nodejs 4.x 的项目, 需要升级到6.9.5(当时最新的稳定版本)以改善性能和可靠性.业务中使用到了co, 进程使用 pm2 管理.确保构建脚本能够使用nvm安装nodejs 6.9.5, 本地运行基本ok
nodejs 4.x 的项目, 需要升级到6.9.5(当时最新的稳定版本)以改善性能和可靠性.
业务中使用到了co, 进程使用 pm2 管理.
升级nodejs版本
确保构建脚本能够使用nvm安装nodejs 6.9.5, 本地运行基本ok
从 co 的问题开始
UnhandledPromiseRejectionWarning: Cannot read property 'done' of undefined 复制代码
服务启动时即产生上述报警信息, 服务不可用, 通过搜索发现是存在某个promise最终reject了, 但是没有catch. 知道直接原因是这样, 但没啥帮助, 我上哪去找这种特点的代码.
考虑断点调试
process.on('unhandledRejection', function(reason, p){
console.log('=======================');
console.log(reason);
console.log(p);
});
复制代码
上述代码加到服务开始启动, 本地调试启动, 发现一切正常 -_-b
不复现问题, 回顾整个问题, 目测可能是 测试环境 问题, 先看看nodejs版本吧
console.log(process.versions) 复制代码
竟然nodejs版本还是旧版本
pm2 的问题
能决定nodejs版本的途径就只有进程启动了, 哪问题就落到 pm2 这边了, 去检查pm2的进程配置
> 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模块来启动子进程.
进一步的, cluster启动子进程是用fork()启动的, 子进程的版本和父进程版本应该是一致的. 大概率是这个原因.
简单重启daemon进程的办法是 pm2 kill 干掉daemon和所有worker进程后, 重新 pm2 start . 一番折腾后的结论:
- daemon进程更新, 除了
pm2 kill && pm2 ping可以重启daemon外, 还可以pm2 update它还会使用当前版本pm2 - 想要让app生效还是建议重新添加app,
pm2 delete app.json && pm2 start app.json
测试环境重启了pm2 daemon进程后, 启动仍旧是前文遇到的报警, 但 node.js version 输出是符合预期了.
虽然没解决问题, 但升级版本是必须的. 继续看看, 收集线索
回到 co 的问题
现在nodejs版本一致, 但是测试环境报警, 本地不复现, 可能还是环境问题, 继续看进程配置, 发现 interpreter args: --harmony
这个是旧版本nodejs为了兼容新的特性加的开关, 考虑到错误堆栈是从co中过来的, 查看co的文档
按理v4+之后就不需要加这个开关, 暂且不关心为什么加这个开关, 目前能找到的差异就是这个地方, 先本地加上这个开关运行看看
结果 复现相同的报警 , 本地和测试环境现象一致
接下来就好办了, 到app.json中删除这段配置, pm2 delete app.json && pm2 start app.json 重新启动app, 问题解决.
总结
- pm2 cluster_mode 升级nodejs时需要同步更新daemon进程
- worker进程的配置也需要手工更新
- nodejs不会保证部分实验性开关的兼容性
实际遇到的环境问题可能都是混杂多个关键原因, 必须得解决所有的原因才能正常工作.
错误才是常态, 正确是一连串的偶然组合在一起
遗留疑问: --harmony 怎么加上去的
了解cluster的同学应该知道 fork() 只有一个参数 环境变量, 那就有些奇怪的地方了.
一种可能是 pm2 daemon 启动时加上去的, 但也不合逻辑, daemon可能会管理多个项目, 有的是cluster, 有的不是.
只是猜测显然不行, 看源码吧
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
大家好,我是猫眼娱乐前端技术专家-曹宇,我主要负责猫眼娱乐电影选座交易业务前端, 除了大家能看到的各种 Web 页面, 还有小程序端和供应链端. 同时负责猫眼内部的前端基础设施, 质量保证相关工作。
猫眼电影小程序从零发展到票务类别第一, 主要关注点都集中在线上, 这次分享的是一个线上 线下联动的活动, 从开发到上线后遇到的一些有趣的事情, 除了小程序技术的深度应用, 还包括产品 运营层面的思考.
本周六(10月21日)我会做客掘金Bilibili直播间为大家做一场《打码指南:由猫眼线下扫码1分购谈起》的直播。直播中我们也会送出技术图书,大号定制鼠标垫等奖品,欢迎周六下午大家与我们一起交流。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Algorithms + Data Structures = Programs
Niklaus Wirth / Prentice Hall / 1975-11-11 / GBP 84.95
It might seem completely dated with all its examples written in the now outmoded Pascal programming language (well, unless you are one of those Delphi zealot trying to resist to the Java/.NET dominanc......一起来看看 《Algorithms + Data Structures = Programs》 这本书的介绍吧!