How does the Node JS process exit?
There are several factors that can cause the Node JS process to exit. Among these factors, some are preventable, such as the code throws an exception; some are not preventable, such as memory exhaustion. process
global variable is an Event Emitter instance if the process elegant exit, process
will distribute a exit
event. Application code can listen to this event to do the final cleanup work.
The following table lists the factors that can cause the Node JS process to exit.
Operate | For example |
---|---|
Log out manually | process.exit(1) |
Uncaught exception | throw new Error() |
Unhandled promise rejection | Promise.reject() |
Unhandled error event | EventEmitter#emit('error') |
Unprocessed signal | kill <PROCESS_ID> |
Take the initiative to exit
process.exit(code)
is the most direct way to end the process. The code
parameter is optional and can be any number between 0 and 255, and the default is 0. 0 means the process is executed successfully, and a number other than 0 means the process has failed to execute.
When process.exit()
is used, the console will not have any output, if we want to be like console output in the process launched when some of the error description message, you need to output an error message is displayed before the call.
node --eval="process.exit(42)" echo $?
The above code exits the NodeJS process directly, and there is no output information from the command line. When the user encounters a process exit, he cannot obtain valid error information.
function checkConfig(config) { if (!config.host) { console.error("Configuration is missing 'host' parameter!"); process.exit(1); } }
In the above code, we output a clear error message before the process exits.
process.exit()
function is very powerful, but we should not use it in the tool library. If an error is encountered in the tool library, we should throw it in the form of an exception, so that the application code can decide how to handle the error.
Exceptions, Rejections and Emitted Errors
process.exit()
It is very useful in scenarios such as application startup configuration checks, but it is not applicable when dealing with runtime exceptions, and we need other tools.
For example, when the application is processing an HTTP request, an error should not cause the process to terminate. Instead, we should return a response containing the error message.
Error
The class can contain data that describes the details of the error occurrence, such as call stack and error text. Normally we would define XXXError specific scene, these XXXError system inherited Error
class.
When we use the throw
keyword or code logic error, an error will be thrown. At this point, the system call stack will be released, and each function will exit until it encounters a try/catch statement that wraps the current call. If there is no try/catch statement, the error will be considered an uncaught exception.
Typically, in NodeJS application, we will define a Error class
code
attribute, as used to describe the specific error code error, the advantage of this is that the error code may be unique, while the error code that is readable. At the same time, we can also cooperatemessage
attributes to describe the specific error message.
When an uncaught exception is thrown, the console will print the call stack and the process exits with the exit status code 1.
/tmp/infohubblog.js:1 throw new TypeError('invalid value'); ^ Error: invalid value at Object.<anonymous> (/tmp/infohubblog.js:2:11) ... TRUNCATED ... at internal/main/run_main_module.js:17:47
This console output information indicates an error occurred in the infohubblog.js
first 11 in the second row.
Global variables process
is Event Emitter instance, you can listen uncaughtException
to handle these uncaught exception events. The following code shows how to use:
const logger = require("./lib/logger.js"); process.on("uncaughtException", (error) => { logger.send("An uncaught exception has occured", error, () => { console.error(error); process.exit(1); }); });
Promise Rejection is similar to throwing an exception. We can call reject()
the function or async
arriving rejected state is throwing an exception to the promise function. The functions of the following two pieces of code are similar.
Promise.reject(new Error("oh no")); (async () => { throw new Error("oh no"); })();
Currently, in NodeJS 14, Promise Rejection will not cause the process to exit. In subsequent versions, Promise Rejection may cause the process to exit.
Below is a sample console output of an uncaught Promise Rejection.
(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().
We can listen unhandledRejection
to handle Rejection uncaught event sample code is as follows:
process.on("unhandledRejection", (reason, promise) => {});
Event Emitter is a basic module in NodeJS, which is widely used. When the Event Emitter of the error
event is not handled, Event Emitter will throw an error, and it will cause the process to exit. Below is error
the console output of an Event Emitter .
events.js:306 throw err; // Unhandled 'error' 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: 'ERR_UNHANDLED_ERROR', context: undefined }
Therefore, when we use the Event Emitter to ensure monitor the error
event, so that when an error occurs, you can enable applications to handle these errors, to avoid Ben collapse.
Signal
Signals are operational information and provide an inter-process communication mechanism. The signal is usually a number, but a character string can also be used to identify it. For example, SIGKILL
identification number 9. Different operating systems have different definitions of signals. The following table lists the basic common signal definitions.
name | number | Can it be handled | NodeJS default behaviour | The meaning of the signal |
---|---|---|---|---|
SIGHUP | 1 | Yes | quit | The parent command line is closed |
SIGINT | 2 | Yes | quit | Attempt to interrupt the command line, ie Ctrl + C |
SIGQUIT | 3 | Yes | quit | Try to exit from the command line, ie Ctrl + Z |
SIGKILL | 9 | No | quit | Force process to exit |
SIGUSR1 | 10 | Yes | Start the debugger | User-defined signal |
SIGUSR2 | 12 | Yes | quit | User-defined signal |
SIGTERM | 15 | Yes | quit | The process exits gracefully |
SIGSTOP | 19 | No | quit | The process is forcibly stopped |
In this table, whether it can be processed indicates whether the signal can be received and processed by the process. The default behaviour of NodeJS represents the default action performed by the process after receiving this signal.
We can monitor these signals in the following ways.
console.log(`Process ID: ${process.pid}`); process.on("SIGHUP", () => console.log("Received: SIGHUP")); process.on("SIGINT", () => console.log("Received: SIGINT")); setTimeout(() => {}, 5 * 60 * 1000); // keep process alive
Run a command line window this code, then press Ctrl + C, will not withdraw from the process at this time, but will receive a print one line in the console SIGINT
log information signal. Create a new command line window, execute the following command, PROCESS_ID is the process ID output by the above program.
kill -s SIGHUP <PROCESS_ID>
By starting a new command line, we send the original to a program that processes SIGHUP
the signal, the original command line window will print a row received the SIGHUP
log information signal.
In NodeJS code, a process can also send signals to other processes. for example:
node -e "process.kill(<PROCESS_ID>, 'SIGHUP')"
This code will also output a first command line window received the SIGHUP
log signal.
If we want to make the process of the first command-line window exit, we can use the following command to achieve.
kill -9 <PROCESS_ID>
In NodeJS, signals are usually used to control the graceful exit of the process. For example, in Kubernetes , when a pod exits, k8s will send a like process in the pod SIGTERM
signals, and start a 30-second timer. The application has 30 seconds to close the connection, save data, etc. If after 30 seconds the process is still alive, k8s will send another SIGKILL
to force the shutdown process.
summary
This article describes several factors that can cause a process to exit, namely:
- Take the initiative to exit
- Uncaught exception, unhandled promise rejection, unhandled Event Emitter error events
- System signal
Be the first to comment on "Node JS process exit?"