在本地Node.js运行子进程时,你不能用npm启动应用程序。在本文,我们列出了Node.js应用程序的最佳实践方式,用代码片段解释了核心问题,重现问题的3步骤。总之,我们不再用npm start命令来运行Lisk Core,而是用本机node命令。

npm及其最著名的“npm start”命令

在JaveScript型项目中,Npm是首选的节点包管理器。你可以将他人的代码包放到自己的项目中,因此不必从零开始编写代码。令Npm出名的另一个原因是,加密行业大范围使用了其脚本命令,其最出名的还是npm start命令,它是node.app.js的安装包(wrapper)。

我们面临的挑战:将app.js文件作为npm子进程运行

许多人不知道的一个问题是,当使用npm start启动node.app.js时,npm实际是将app.js文件作为子进程运行。在99%的情况,你无需担心,但当你在项目中运行子进程时,就会引发麻烦。

为了更好地理解npm与“npm vs node”问题的内在联系,一起来看看Lisk Core的运行。本质上,Lisk Core是一个实现Lisk Protocol的程序,Lisk Protocol中有共识、区块创建、交易处理、节点通信等等。每个计算机都必须设置成允许参与网络的节点。

PM2,一个Node.js应用程序生产进程管理器

在Lisk中,当启动应用程序失败时,我们用PM2重启应用。它是Node.js应用程序的生产进程管理器,内置有负载平衡器。用户可以一直打开应用程序,在不停机的情况下重新加载应用和简化日常系统管理任务。

几周前,我们开放了子进程http-api模块,以便在分配相同资源时,提高Lisk Core应用程序的整体速度。

子进程http_api模块背后的运行原理

http_api能作为子进程,是因为其背后有构建多进程应用的单个功能组件,最大化利用实物处理器的多硬件处理潜力。而且,灵活地设计单个组件,可以巩固多进程。因此单个组件既可单独恢复,出现故障后对其他组件的影响也最小。更多关于子进程的信息可以查看Lisk提案

无法优雅地用npm退出Lisk Core

Lightcurve后端开发人员Lucas Silvestre发现,当用子进程PM2运行http_api模块时,Lisk Core并没有优雅地退出。因此出现一个问题,即使主进程(LiskCore)崩溃,http_api仍在后台运行。

此时,PM2应该会尝试恢复Lisk Core进程,生成一个新http_api进程。但由于进程尚未清理,端口正在使用中,无法生成新进程。导致PM2无法恢复应用程序,这会对正在运行的区块链节点产生很大影响。在这种情况下,用户必须手动重启区块链节点,这是我们绝不想看到的。

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

使用node命令运行Lisk Core

上述的问题让我们认识到npm与node的差别,于是考虑运行Lisk Core的新方式。之前,我们将npm start行业标准作为运行应用程序的首选方法。

后来,我们发现docker-node GitHub存储库可以最佳地实现Dockerizing Node.js应用程序。

“创建映像时,你可以不使用package.json的启动命令,而直接烘焙为映像。第一,可以减少容器内部运行的进程。第二,Node.js进程会取代npm接收SIGTERM和SIGINT等退出信号。”

每当我们退出Lisk Core或应用程序崩溃时,系统都会向应用程序发送一个SIGINT信号。Node.js可以收听此信号并执行清理函数,从而优雅地退出应用程序。目前,我们正在移除各种收听器,将SIGINT信号传送给子进程Node.js,以便优雅地退出这个进程。

如docker-node技术文档所述,npm接收SIGINT信号,不会触发收听器也接收这个信号,导致应用程序无法优雅地清理进程。这也是PM2中的http_api模块一直在后台运行的原因。

用PM2运行节点应用程序的专家Nick Parson认为:当使用PM2时,要保证稳定性最大化和快速启动(无宕机的情况),就需要优雅地关闭应用程序。

终止信号:SIGKILL、SIGTERM和SIGINT

先来深入了解这些信号的作用。这些信号是通知进程终止的部分信号,更多的终止信号可以查看gnu.org上的第24.2.2节文档。

· SIGKILL:“SIGKILL信号用于立即终止程序。不能删除或忽略这个信号。”

· SIGTERM:“SIGTERM信号是用于终止程序的通用信号。与SIGKILL信号不同,可以阻止、删除或忽略这个信号,优雅地终止程序。Shell命令可阻止默认的SIGTERM信号。

· SIGINT:“用户输入INTR(通常是C-c),就会发送SIGINT(中断程序)信号。”但开发人员可能更喜欢用CTRL/CMD+C命令来中断shell中正在运行的进程。

将Docker和PM2移到节点

为了将Docker和PM2移到节点上,我们删掉了npm.start,转而使用node命令。在Dockerfile中,用starter命令启动PM2运行文件。

下图是Docker的一个典型入口点的代码片段。之前,入口点包含 “npm”,“start”。

可以在Lisk的新Lisk Core存储库找到这个文件,我们从Lisk-sdk Monorepo中提取的这个文件。

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

同样,这种方法也适用于pm2-lisk.json文件,这个文件中包含启动Lisk Core的PM2配置。现在,script属性中包含索引文件的相对路径。

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

如何用3个步骤重现问题

有一个GitHub用户EvanTahler创建了一段很酷的代码片段解决了上述问题。

步骤1,创建package.json和app.js

模拟该问题,只需在同一目录中创建两个文件(package.json和app.js)。确保自己的计算机已安装了Node.js的10.x或更高版本,以便使用node命令运行代码片段。无需安装任何代码附件。

Package.json

为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

App.js

为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

说明:代码片段每0.5秒打印一个点,并侦听SIGINT和SIGTERM信号。一旦收到两个终止信号之一,系统将延迟关机5秒(5 * 1000毫秒),并打印出“再见!”

在运行这个代码片段之前,我想让你看看CTRL/CMD+C键如何终止终端进程,请注意带有^C的字符。

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

上图显示在SIGINT信号出现后,Lisk Core运行了整整17分钟才停止。

步骤2,用node运行代码片段

现在我们已经知道如何在终端中表示SIGINT,现在来看看node app.js吧!运行node app.js5秒钟,然后按CTRL/CMD+C键。可以看到node正在处理终止信号,并大约5秒后终止进程。

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

步骤3,使用npm start运行代码片段

当我们使用npm start运行代码片段时,会收到两个终止信号。Start命令将运行子进程node app.js。当接收到^C时,npm进程会终止,并将终止信号传送给子进程,导致主进程终止,而子进程仍然运行5秒之久。

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

正如前面所解释的,在运行带有npm start的应用程序时,当您收听终止信号时,尤其是在操作子进程时,会出现各种各样的问题。

对学习如何设置和运行自己的Lisk节点感兴趣吗?更多信息查看Lisk官网的Lisk Core文档。您可以选择默认的二进制设置来安装。也可以用Docker运行Lisk Core,以支持其他平台或更高级的用户,可以从Lisk Core开始构建。

由于“子进程初始化”,http_api模块无法优雅地退出并继续运行。唯一的退出方法是使用一个shell命令来停止所有节点进程:sudo killall Node(或针对要停止的特定进程ID)。还好,使用node启动应用程序可以轻松地解决这个问题。

处理Node.js应用程序的最佳实践

Node.js的早期贡献者Felix Geisendorfer,,十分了解如何处理崩溃的应用程序:

 为什么Lisk停止使用’ npm start ‘来运行Lisk core的子进程?-LISK应用链

以上文字说明了什么?要避免用npm start启动应用程序,而是使用node。如果出现问题,就优雅地退出这个进程。在此,Felix建议使用PM2之类的高级工具来处理恢复和重新启动应用程序。

我们从中学到,标准不是一成不变的。有时候,简化问题,用简单的node命令来运行会更好。

为了总结上述工作,我们将PM2运行配置和Dockerfile中的node src/indexnpm 更改为npm start命令。现在,应用程序接收到一个SIGINT信号后,节点进程可以直接接收这个信号,并可以将SIGINT信号传送给它的子进程,这样可以优雅地退出每个进程。

因此,用PM2可以轻松地重启应用程序,无宕机时间。这个设置,会让我们的应用程序更加稳定,也有助于创建一个稳定的区块链网络。

Lisk授予个人权利来创建一个更加去中心化、高效和透明的全球经济。欢迎您加入我们。