美文网首页我爱编程翻译系列
[译]掌握Node.js的核心模块-Process

[译]掌握Node.js的核心模块-Process

作者: AltairLu | 来源:发表于2017-10-25 16:32 被阅读0次

[译]掌握Node.js的核心模块-Process

在这篇文章中,我们将学习Node.js的Process模块以及模块里隐藏的宝藏。通读本文后,你在编写生产环境的应用时会更加自信。你将了解Node.js应用中Process的状态、可以正常地关闭应用以及更自信地处理错误

在新的Mastering the Node.js Core Modules 系列中你可以学到核心模块隐藏的或是几乎无人知晓的特性,以及如何去使用这些特性。过一遍Node.js模块中基本要素,你会更加理解Node的运行原理以及如何去处理错误

在这个章节中,我们会看一下Node.js的process模块。这个process对象是EventEmitter的实例。它是一个全局变量,在当前的Node.js进程中提供有关信息。

在 Node.js 的 process 模块中需要注意的事件(Events)

因为process模块是EventEmitter的实例,所以你像其他的EventEmitter的实例一样用.on()方法来订阅它的事件:

process.on('eventName', () => {
  //do something
})

uncaughtException

如果 Javascript 未捕获的异常,沿着代码调用路径反向传递回 Event loop,这个事件就会被触发。

默认情况下,如果没有对uncaughtException事件添加任何监听器, Node.js 默认情况下会将这些异常堆栈打印到stderr,然后进程退出。 如果你添加了一个监听器就会覆盖上述默认行为

process.on('uncaughtException', (err) => {
  // here the 1 is a file descriptor for STDERR
  //这里的 l 是 STDERR 对应的一个文件描述符
  fs.writeSync(1, `Caught exception: ${err}\n`)
})

在过去几年中,我们见到很多对于这个事件的错误的运用。当使用这个process模块中的uncaughtException事件时,有以下几点十分重要的建议需要注意

  • 如果uncaughtException事件发生了,这表明你的应用正处在一个未定义的状态中
  • 十分不建议借助uncaughtException事件尝试恢复应用正常运行,这种操作是不安全
  • 这个事件的处理器应该只用来进行已分配资源的同步清理操作(the handler should only be used for synchronous cleanup of allocated resources)
  • 如果处理这个事件的函数内有异常抛出且未被捕获的话,应用会立刻退出
  • 你应该使用外部工具来监控你的进程并且在必要时重启它(比如当它崩溃的时候)

unhandledRejection

如下示例代码

const fs = require('fs-extra')

fs.copy('/tmp/myfile', '/tmp/mynewfile')
  .then(() => console.log('success!'))

如果需要复制的文件不存在的话会发生什么事?这个答案取决于你的Node.js的版本,通常在4及4以下的版本中,进程不会报错而是直接退出,留下坐在电脑前一脸懵逼的你。
而在最近的Node.js版本中,你会得到如下错误提示

(node:28391) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): undefined
(node:28391) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

这段信息提示我们用来拷贝文件的promise中有个错误没有被捕获,正确的代码应该这么写:

fs.copy('/tmp/myfile', '/tmp/mynewfile')
  .then(() => console.log('success!'))
  .catch(err => console.error(err))

Promise rejections未处理的问题其实跟uncaughtException一样 - 你的 Node.js 进程会处于一个未定义的状态,更糟糕的是,这可能会引起文件描述符未关闭( file descriptor failure )以及内存泄漏。在这种情况下,你最好还是重新启动Node.js进程。

综上所述,你应该给unhandledRejection事件添加监听器并且使用process.exit(1)来退出进程

推荐阅读 Matteo Collina 的 make-promises-safe package,它可以解决你的困惑

Node.js 信号事件

当Node.js进程接收到一个 POSIX 的信号时,会触发信号事件,接下来详细阐述其中最重要的两个,STGTERMSIGUSR1

点这里 可以找到所有的支持的信号

STGTERM

STGTERM信号会发送给Node进程以请求终止进程。它与SIGKILL信号不同,可以被监听或者无视

这样可以通过释放进程分配的资源(比如文件描述符或者数据库链接)来以很好的方式关闭进程。这种关闭进程的方式被称为 graceful shutdown

事实上,在演绎一个 graceful shutdown 之前必须经历以下这几个步骤:

  1. 应用收到了停止通知(收到SIGTERM信号)
  2. 应用通知负载均衡器(load balancers)不要再处理新的请求
  3. 应用完成所有正在进行的请求
  4. 接下来,正确释放所有的资源(像数据库连接)
  5. 应用用“成功”的状态码退出(process.exit()

阅读这篇文章了解更多 graceful shutdown in Node.js

SIGUSR1

在 POSIX 的标准中, SIGUSR1SIGUSR2 是可以用在用户定义的条件下,Node.js 选择用这个事件来启动内置的调试器

你可以用以下命令来给进程发送SIGUSR1信号

kill -USR1 PID_OF_THE_NODE_JS_PROCESS

一旦你这么做了,所涉及到的Node进程会让你知道调试器正在运行

Starting debugger agent.
Debugger listening on [::]:5858

Process 模块公开的方法和值

process.cwd()

这个方法返回Node进程的当前工作目录(绝对路径)

$ node -e 'console.log(`Current directory: ${process.cwd()}`)'
Current directory: /Users/gergelyke/Development/risingstack/risingsite_v2

如果你想改变它,可以调用process.chdir(path)这个方法

process.env

该属性返回一个包含用户环境的对象,就像 environ

如果你在根据十二要素应用宣言(the 12-factor application principles)来构建应用程序,你会十分依赖它;就像 third principle of a twelve-factor application中说的:all configurations should be stored in the user environment

环境变量应该是首选,因为这样就可以在不更改代码的前提下轻松更改不同的部署环境。不像配置文件(config files),它们基本不可能影响到代码库

值得一提的是,你可以更改process.env中的值,虽然它不会反映到用户环境中去

process.exit([code])

这个方法告诉 Node进程用一个退出的状态码来同步地终止进程,这么会有一些很重要的后果:

  • 它会强制让进程尽快终止
    • 哪怕有些异步操作仍然在进行
    • 因为STDOUTSTDERR的输出的异步的,所以有些日志信息可能会丢失
  • 在大多数情况下,不推荐使用process.exit() - 你可以让代码运行完毕自动退出作为替代

process.kill(pid, [signal])

你可以用这个方法来发送各种 POSIX 信号给各种进程。你不仅仅可以像它名字写的那样用来杀死进程。这个命令就像一个信号发送器(包括杀死系统调用)

Node.js 使用的退出代码

如果一切正常,Node.js 会用退出码 0来退出。如果进程因为某种错误而退出,你将会获得以下状态码中的一种:

  • 1: 没有被uncaughtException事件的监听器处理的致命异常
  • 5: V8中的致命错误(比如分配内存失败)
  • 9:无效的参数,比如指定了未知的选项或者一个选项引用了一个未设定的值

这些只是比较常见的退出码,想看所有的状态码,请看 https://nodejs.org/api/process.html#process_exit_codes

相关文章

网友评论

    本文标题: [译]掌握Node.js的核心模块-Process

    本文链接:https://www.haomeiwen.com/subject/bboqpxtx.html