>  기사  >  웹 프론트엔드  >  Node.js 프로세스를 적극적으로 종료하는 여러 방법에 대한 자세한 설명

Node.js 프로세스를 적극적으로 종료하는 여러 방법에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2021-04-22 09:47:575983검색

이 글에서는 Node 프로세스 종료를 적극적으로 실행하는 몇 가지 방법을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

Node.js 프로세스를 적극적으로 종료하는 여러 방법에 대한 자세한 설명

Node.js 프로세스가 종료되는 데에는 여러 가지 이유가 있습니다. 이들 중 일부는 오류 발생과 같이 피할 수 있는 반면, 다른 일부는 메모리 부족과 같이 예방할 수 없습니다. 전역 프로세스는 실행이 정상적으로 종료될 때 exit 이벤트를 발생시키는 이벤트 이미터 인스턴스입니다. 그런 다음 프로그램 코드는 이 이벤트를 수신하여 최종 동기화 정리 작업을 수행할 수 있습니다. process 是一个 Event Emitter 实例,当执行正常退出时,将发出一个 exit 事件。然后程序代码可以通过侦听这个事件来执行最后的同步清理工作。

相关推荐:《nodejs 教程

下面是可以主动触发进程终止的一些方法:

관련 권장 사항: "nodejs tutorial"
操作 例子
手动流程退出 process.exit(1)
未捕获的异常 throw new Error()
未兑现的 promise Promise.reject()
忽略的错误事件 EventEmitter#emit('error')
未处理的信号 $ kill ba688ccdd41ae5bf1f639b6cc232fa52
다음을 수행할 수 있습니다. 프로세스 종료를 적극적으로 트리거하는 몇 가지 방법: 🎜🎜
작업
수동 프로세스 종료🎜 process.exit(1)🎜🎜
잡히지 않은 예외🎜 새 오류 발생() 🎜🎜
이행되지 않은 약속🎜 Promise.reject()🎜🎜
무시된 오류 이벤트🎜 EventEmitter#emit('error ')🎜🎜
처리되지 않은 신호🎜 $ kill ba688ccdd41ae5bf1f639b6cc232fa52🎜🎜🎜🎜

그 중 다수는 발견되지 않은 오류나 처리되지 않은 약속과 같이 실수로 트리거되지만 일부는 프로세스를 직접 종료하기 위해 생성됩니다.

프로세스 종료

process.exit(code)를 사용하는 것이 프로세스를 종료하는 가장 직접적인 방법입니다. 이는 프로세스가 수명 주기의 끝에 도달했음을 알 때 유용합니다. code 값은 선택 사항이며 기본값은 0이고 최대값은 255입니다. 0은 프로세스가 성공적으로 실행되었음을 나타내고 0이 아닌 숫자는 문제가 발생했음을 나타냅니다. 이 값은 다양한 외부 도구에서 사용할 수 있습니다. 예를 들어, 테스트 스위트가 실행될 때 0이 아닌 값은 테스트가 실패했음을 나타냅니다. process.exit(code) 来终止进程是最直接的方法。这在当你知道自己的过程已经到了生命周期的尽头时非常有用。  code 值是可选的,默认值为0,最大可以设为 255。0 表示进程运行成功,而任何非零的数字都表示发生了问题。这些值可以被许多不同的外部工具使用。例如当测试套件运行时,非零值表示测试失败。

直接调用 process.exit() 时,不会向控制台写入任何隐式文本。如果你编写了以错误表示形式调用此方法的代码,则你的代码应该用户输出错误来帮助他们解决问题。例如运行以下代码:

$ node -e "process.exit(42)"
$ echo $?

在这种情况下,单行的 Node.js 程序不会输出任何信息,尽管 shell 程序确实会打印退出状态。遇到这样的进程退出,用户将无法理解究竟发生了什么事情。所以要参考下面这段程序配置错误时会执行的代码:

function checkConfig(config) {
  if (!config.host) {
    console.error("Configuration is missing 'host' parameter!");
    process.exit(1);
  }
}

在这种情况下,用户没会很清楚发生了什么。他们运行这个程序,将错误输出到控制台上,并且他们能够纠正这个问题。

process.exit() 方法非常强大。尽管它在程序代码中有自己的用途,但实际上绝对不应该将其引入可重用的库中。如果在库中确实发生了错误,则应抛出这个错误,以便程序可以决定应该如何处理它。

exceprion、rejection 和发出的 Error

虽然 process.exit() 很有用,但对于运行时错误,你需要使用其他工具。例如当程序正在处理 HTTP 请求时,一般来说错误不应该终止进程,而是仅返回错误响应。发生错误的位置信息也很有用,这正是应该抛出 Error 对象的地方。

Error 类的实例包含对导致错误的原因有用的元数据,例如栈跟踪信息和消息字符串。从 Error 扩展你自己的错误类是很常见的操作。单独实例化 Error 不会有太多副作用,如果发生错误则必须抛出。

在使用 throw 关键字或发生某些逻辑错误时,将引发 Error。发生这种情况时,当前栈将会“展开”,这意味着每个函数都会退出,直到一个调用函数将调用包装在 try/catch 语句中为止。遇到此语句后,将调用 catch 分支。如果错误没有被包含在 try/catch 中,则该错误被视为未捕获。

虽然你应该使用带有 Errorthrow 关键字,例如 throw new Error('foo'),但从技术上讲,你可以抛出任何东西。一旦抛出了什么东西,它就被认为是一个例外。抛出 Error 实例非常重要,因为捕获这些错误的代码很可能会期望得到错误属性。

Node.js 内部库中常用的另一种模式是提供一个 .code 属性,该属性是一个字符串值,在发行版之间应保持一致。比如错误的 .code 值是 ERR_INVALID_URI,即使是供人类可读的 .message 属性可能会更改,但这个 code 值也不应被更改。

可悲的是,一种更常用的区分错误的模式是检查 .message 属性,这个属性通常是动态的,因为可能回需要修改拼写错误。这种方法是很冒险的,也是容易出错的。 Node.js 生态中没有完美的解决方案来区分所有库中的错误。

当引发未捕获的错误时,控制台中将打印栈跟踪信息,并且进程将回以退出状态 1 终止。这是此类异常的例子:

/tmp/foo.js:1
throw new TypeError('invalid foo');
^
Error: invalid foo
    at Object.<anonymous> (/tmp/foo.js:2:11)
    ... TRUNCATED ...
    at internal/main/run_main_module.js:17:47

上面的栈跟踪片段表明错误发生在名为 foo.js 的文件的第 2 行第 11 列。

全局的 process 是一个事件发射器,可以通过侦听 uncaughtException 事件来拦截未捕获的错误。下面是一个使用它的例子,在退出前拦截错误以发送异步消息:

const logger = require(&#39;./lib/logger.js&#39;);
process.on(&#39;uncaughtException&#39;, (error) => {
  logger.send("An uncaught exception has occured", error, () => {
    console.error(error);
    process.exit(1);
  });
});

Promise 拒绝与抛出错误非常相似。如果 Promise 中的 reject() 方法被调用,或者在异步函数中引发了错误,则 Promise 可以拒绝。在这方面,以下两个例子大致相同:

Promise.reject(new Error(&#39;oh no&#39;));

(async () => {
  throw new Error(&#39;oh no&#39;);
})();

这是输出到控制台的消息:

(node:52298) UnhandledPromiseRejectionWarning: Error: oh no
    at Object.<anonymous> (/tmp/reject.js:1:16)
    ... TRUNCATED ...
    at internal/main/run_main_module.js:17:47
(node:52298) UnhandledPromiseRejectionWarning: Unhandled promise
  rejection. This error originated either by throwing inside of an
  async function without a catch block, or by rejecting a promise
  which was not handled with .catch().

与未捕获的异常不同,从 Node.js v14 开始,这些 rejection 不会使进程崩溃。在未来的 Node.js 版本中,会使当前进程崩溃。当这些未处理的 rejection 发生时,你还可以拦截事件,侦听 process

process.exit()를 직접 호출하면 암시적 텍스트가 콘솔에 기록되지 않습니다. 오류 표시와 함께 이 메서드를 호출하는 코드를 작성하는 경우 코드는 사용자가 문제를 해결하는 데 도움이 되도록 오류를 출력해야 합니다. 예를 들어, 다음 코드를 실행하세요: 🎜
process.on(&#39;unhandledRejection&#39;, (reason, promise) => {});
🎜 이 경우, 쉘 프로그램이 종료 상태를 인쇄하더라도 단일 행 Node.js 프로그램은 어떤 정보도 출력하지 않습니다. 이러한 프로세스 종료가 발생하면 사용자는 무슨 일이 일어났는지 이해할 수 없습니다. 따라서 프로그램 구성이 잘못되었을 때 실행되는 다음 코드를 참고하시기 바랍니다. 🎜
events.js:306
    throw err; // Unhandled &#39;error&#39; event
    ^
Error [ERR_UNHANDLED_ERROR]: Unhandled error. (undefined)
    at EventEmitter.emit (events.js:304:17)
    at Object.<anonymous> (/tmp/foo.js:1:40)
    ... TRUNCATED ...
    at internal/main/run_main_module.js:17:47 {
  code: &#39;ERR_UNHANDLED_ERROR&#39;,
  context: undefined
}
🎜이 경우 사용자는 무슨 일이 일어나고 있는지 알 수 없습니다. 그들은 프로그램을 실행하고 콘솔에 오류를 인쇄하며 문제를 수정할 수 있습니다. 🎜🎜process.exit() 메서드는 매우 강력합니다. 프로그램 코드에서 고유한 용도가 있지만 재사용 가능한 라이브러리에 도입해서는 안 됩니다. 라이브러리에서 오류가 발생하면 프로그램이 이를 처리하는 방법을 결정할 수 있도록 이 오류가 발생해야 합니다. 🎜🎜🎜예외, 거부 및 오류 발생🎜🎜🎜process.exit()이 유용하지만 런타임 오류의 경우 다른 도구를 사용해야 합니다. 예를 들어, 프로그램이 HTTP 요청을 처리할 때 일반적으로 오류로 인해 프로세스가 종료되지 않고 오류 응답만 반환되어야 합니다. 오류가 발생한 위치, 즉 Error 개체가 발생해야 하는 위치를 아는 것도 유용합니다. 🎜🎜 Error 클래스의 인스턴스에는 스택 추적 정보, 메시지 문자열 등 오류 원인에 대한 유용한 메타데이터가 포함되어 있습니다. Error에서 자신만의 오류 클래스를 확장하는 것이 일반적인 관행입니다. Error를 인스턴스화하는 것만으로는 부작용이 많지 않으며 오류가 발생하면 발생해야 합니다. 🎜🎜throw 키워드를 사용하거나 특정 논리 오류가 발생하면 오류가 발생합니다. 이런 일이 발생하면 현재 스택이 "언롤링"됩니다. 즉, 호출 함수가 호출을 try/catch 문으로 래핑할 때까지 모든 함수가 종료됩니다. 이 문이 발견되면 catch 분기가 호출됩니다. 오류가 try/catch로 묶이지 않은 경우 오류는 발견되지 않은 것으로 간주됩니다. 🎜🎜기술적으로는 Error와 함께 throw 키워드를 사용해야 하지만(예: throw new Error('foo')) 무엇이든 던질 수 있습니다. 무언가가 던져지면 예외로 간주됩니다. 이러한 오류를 포착하는 코드는 오류 속성을 예상할 가능성이 높기 때문에 Error 인스턴스를 발생시키는 것이 중요합니다. 🎜🎜Node.j 내부 라이브러리에서 일반적으로 사용되는 또 다른 패턴은 A를 제공하는 것입니다. 릴리스 간에 일관성을 유지해야 하는 문자열 값인 .code 속성입니다. 예를 들어, 잘못된 .code 값은 ERR_INVALID_URI입니다. 사람이 읽을 수 있는 .message 속성이 변경될 수 있더라도 이 코드는 값도 변경하면 안 됩니다. 🎜🎜안타깝게도 오류를 구별하는 더 일반적인 패턴은 <code>.message 속성을 ​​확인하는 것입니다. 이는 철자 오류를 수정해야 할 수 있으므로 일반적으로 동적입니다. 이 방법은 매우 위험하고 오류가 발생하기 쉽습니다. Node.js 생태계에는 모든 라이브러리의 버그를 구별할 수 있는 완벽한 솔루션이 없습니다. 🎜🎜잡히지 않은 오류가 발생하면 스택 추적이 콘솔에 인쇄되고 프로세스는 종료 상태 1로 종료됩니다. 다음은 이러한 예외의 예입니다. 🎜
#!/usr/bin/env node
console.log(`Process ID: ${process.pid}`);
process.on(&#39;SIGHUP&#39;, () => console.log(&#39;Received: SIGHUP&#39;));
process.on(&#39;SIGINT&#39;, () => console.log(&#39;Received: SIGINT&#39;));
setTimeout(() => {}, 5 * 60 * 1000); // keep process alive
🎜위의 스택 추적 조각은 foo.js라는 파일의 2행, 11열에서 오류가 발생했음을 나타냅니다. 🎜🎜전역 프로세스uncaughtException 이벤트를 수신하여 포착되지 않은 오류를 가로챌 수 있는 이벤트 방출기입니다. 다음은 이를 사용하는 예입니다. 종료하기 전에 오류를 가로채서 비동기 메시지를 보냅니다. 🎜
$ kill -s SIGHUP <PROCESS_ID>
🎜약속 거부는 오류를 던지는 것과 매우 유사합니다. Promise의 reject() 메서드가 호출되거나 비동기 함수에서 오류가 발생하면 Promise가 거부될 수 있습니다. 이와 관련하여 다음 두 가지 예는 거의 동일합니다. 🎜
$ node -e "process.kill(<PROCESS_ID>, &#39;SIGHUP&#39;)"
🎜콘솔에 인쇄되는 메시지는 다음과 같습니다. 🎜
$ kill -9 <PROCESS_ID>
🎜잡히지 않는 예외와 달리 Node.js v14부터 이러한 거부는 프로세스를 중단시키지 않습니다. 향후 Node.js 버전에서는 이로 인해 현재 프로세스가 중단됩니다. 처리되지 않은 거부가 발생할 때 이벤트를 가로채서 process 개체에서 다른 이벤트를 수신할 수도 있습니다. 🎜
process.on(&#39;unhandledRejection&#39;, (reason, promise) => {});

事件发射器是 Node.js 中的常见模式,许多对象实例都从这个基类扩展而来,并在库和程序中使用。它们非常欢迎,值得和 error 与 rejection 放在一起讨论。

当事件发射器发出没有侦听器的 error 事件时,将会抛出所发出的参数。然后将抛出出一个错误并导致进程退出:

events.js:306
    throw err; // Unhandled &#39;error&#39; event
    ^
Error [ERR_UNHANDLED_ERROR]: Unhandled error. (undefined)
    at EventEmitter.emit (events.js:304:17)
    at Object.<anonymous> (/tmp/foo.js:1:40)
    ... TRUNCATED ...
    at internal/main/run_main_module.js:17:47 {
  code: &#39;ERR_UNHANDLED_ERROR&#39;,
  context: undefined
}

确保在你使用的事件发射器实例中侦听 error 事件,以便你的程序可以正常处理事件而不会崩溃。

信号

信号是操作系统提供的机制,用于把用数字表示的消息从一个程序发送到另一个程序。这些数字通常用等价的常量字符串来表示。例如,信号 SIGKILL 代表数字信号 9。信号可以有不同的用途,但通常用于终止程序。

不同的操作系统可以定义不同的信号,但是下面列表中的信号一般是通用的:

名称 编号 可处理 Node.js 默认 信号用途
SIGHUP 1 终止 父终端已关闭
SIGINT 2 终止 终端试图中断,按下 Ctrl + C
SIGQUIT 3 终止 终端试图退出,按下 Ctrl + D
SIGKILL 9 终止 进程被强行杀死
SIGUSR1 10 启动调试器 用户定义的信号1
SIGUSR2 12 终止 用户定义的信号2
SIGTERM 12 终止 代表优雅的终止
SIGSTOP 19 终止 进程被强行停止

如果程序可以选择实现信号处理程序,则 Handleable 一列则为。为的两个信号无法处理。 Node.js 默认 这一列告诉你在收到信号时,Node.js 程序的默认操作是什么。最后一个信号用途指出了信号对应的作用。

在 Node.js 程序中处理这些信号可以通过侦听 process 对象上的更多事件来完成:

#!/usr/bin/env node
console.log(`Process ID: ${process.pid}`);
process.on(&#39;SIGHUP&#39;, () => console.log(&#39;Received: SIGHUP&#39;));
process.on(&#39;SIGINT&#39;, () => console.log(&#39;Received: SIGINT&#39;));
setTimeout(() => {}, 5 * 60 * 1000); // keep process alive

在终端窗口中运行这个程序,然后按 Ctrl + C,这个进程不会被终止。它将会声明已接收到 SIGINT 信号。切换到另一个终端窗口,并根据输出的进程 ID 值执行以下命令:

$ kill -s SIGHUP <PROCESS_ID>

这演示了一个程序怎样向另一个程序发送信号,并且在第一个终端中运行的 Node.js 程序中输出它所接收到的 SIGHUP 信号。

你可能已经猜到了,Node.js 也能把命令发送到其他程序。可以用下面的命令以把信号从临时的 Node.js 进程发送到你现有的进程:

$ node -e "process.kill(<PROCESS_ID>, &#39;SIGHUP&#39;)"

这还会在你的第一个程序中显示 SIGHUP 消息。现在,如果你想终止第一个进程,要运行下面的命令向其发送不能处理的 SIGKILL 信号:

$ kill -9 <PROCESS_ID>

这时程序应该结束。

这些信号在 Node.js 程序中经常用于处理正常的关闭事件。例如,当 Kubernetes Pod 终止时,它将向程序发送 SIGTERM 信号,之后启动 30 秒计时器。然后程序可以在这 30 秒内正常关闭自己,关闭连接并保存数据。如果该进程在此计时器后仍保持活动状态,则 Kubernetes 将向其发送一个 SIGKILL

更多编程相关知识,请访问:编程视频!!

위 내용은 Node.js 프로세스를 적극적으로 종료하는 여러 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제