在 Node.js 退出之前执行清理操作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14031763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Doing a cleanup action just before Node.js exits
提问by Erel Segal-Halevi
I want to tell Node.js to always do something just before it exits, for whatever reason — Ctrl+C, an exception, or any other reason.
我想告诉 Node.js 总是在它退出之前做一些事情,不管是什么原因—— Ctrl+ C、异常或任何其他原因。
I tried this:
我试过这个:
process.on('exit', function (){
console.log('Goodbye!');
});
I started the process, killed it, and nothing happened. I started it again, pressed Ctrl+C, and still nothing happened...
我开始了这个过程,杀死了它,什么也没发生。我再次启动它,按Ctrl+ C,仍然没有发生任何事情......
回答by Emil Condrea
UPDATE:
更新:
You can register a handler for process.on('exit')and in any other case(SIGINTor unhandled exception) to call process.exit()
您可以注册一个处理程序,process.on('exit')并在任何其他情况下(SIGINT或未处理的异常)调用process.exit()
process.stdin.resume();//so the program will not close instantly
function exitHandler(options, exitCode) {
if (options.cleanup) console.log('clean');
if (exitCode || exitCode === 0) console.log(exitCode);
if (options.exit) process.exit();
}
//do something when app is closing
process.on('exit', exitHandler.bind(null,{cleanup:true}));
//catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
// catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', exitHandler.bind(null, {exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));
//catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));
回答by CanyonCasa
The script below allows having a single handler for all exit conditions. It uses an app specific callback function to perform custom cleanup code.
下面的脚本允许对所有退出条件使用单个处理程序。它使用特定于应用程序的回调函数来执行自定义清理代码。
cleanup.js
清理.js
// Object to capture process exits and call app specific cleanup function
function noOp() {};
exports.Cleanup = function Cleanup(callback) {
// attach user callback to the process event emitter
// if no callback, it will still exit gracefully on Ctrl-C
callback = callback || noOp;
process.on('cleanup',callback);
// do app specific cleaning before exiting
process.on('exit', function () {
process.emit('cleanup');
});
// catch ctrl+c event and exit normally
process.on('SIGINT', function () {
console.log('Ctrl-C...');
process.exit(2);
});
//catch uncaught exceptions, trace, then exit normally
process.on('uncaughtException', function(e) {
console.log('Uncaught Exception...');
console.log(e.stack);
process.exit(99);
});
};
This code intercepts uncaught exceptions, Ctrl+Cand normal exit events. It then calls a single optional user cleanup callback function before exiting, handling all exit conditions with a single object.
此代码拦截未捕获的异常、Ctrl+C和正常退出事件。然后在退出之前调用一个可选的用户清理回调函数,用一个对象处理所有退出条件。
The module simply extends the process object instead of defining another event emitter. Without an app specific callback the cleanup defaults to a no op function. This was sufficient for my use where child processes were left running when exiting by Ctrl+C.
该模块只是扩展了流程对象,而不是定义另一个事件发射器。如果没有特定于应用程序的回调,则清理默认为无操作功能。这对于我使用Ctrl+退出时子进程仍然运行的情况来说已经足够了C。
You can easily add other exit events such as SIGHUP as desired. Note: per NodeJS manual, SIGKILL cannot have a listener. The test code below demonstrates various ways of using cleanup.js
您可以根据需要轻松添加其他退出事件,例如 SIGHUP。注意:根据 NodeJS 手册,SIGKILL 不能有监听器。下面的测试代码演示了使用 cleanup.js 的各种方法
// test cleanup.js on version 0.10.21
// loads module and registers app specific cleanup callback...
var cleanup = require('./cleanup').Cleanup(myCleanup);
//var cleanup = require('./cleanup').Cleanup(); // will call noOp
// defines app specific callback...
function myCleanup() {
console.log('App specific cleanup code...');
};
// All of the following code is only needed for test demo
// Prevents the program from closing instantly
process.stdin.resume();
// Emits an uncaught exception when called because module does not exist
function error() {
console.log('error');
var x = require('');
};
// Try each of the following one at a time:
// Uncomment the next line to test exiting on an uncaught exception
//setTimeout(error,2000);
// Uncomment the next line to test exiting normally
//setTimeout(function(){process.exit(3)}, 2000);
// Type Ctrl-C to test forced exit
回答by light24bulbs
This catches every exit event I can find that can be handled. Seems quite reliable and clean so far.
这会捕获我能找到的可以处理的每个退出事件。到目前为止似乎相当可靠和干净。
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`].forEach((eventType) => {
process.on(eventType, cleanUpServer.bind(null, eventType));
})
回答by user1278519
"exit" is an event that gets triggered when node finish it's event loop internally, it's not triggered when you terminate the process externally.
“退出”是一个事件,当节点在内部完成它的事件循环时被触发,当您在外部终止进程时不会触发它。
What you're looking for is executing something on a SIGINT.
您正在寻找的是在 SIGINT 上执行某些操作。
The docs at http://nodejs.org/api/process.html#process_signal_eventsgive an example:
http://nodejs.org/api/process.html#process_signal_events 上的文档给出了一个例子:
Example of listening for SIGINT:
侦听 SIGINT 的示例:
// Start reading from stdin so we don't exit.
process.stdin.resume();
process.on('SIGINT', function () {
console.log('Got SIGINT. Press Control-D to exit.');
});
Note: this seems to interrupt the sigint and you would need to call process.exit() when you finish with your code.
注意:这似乎会中断 sigint,当您完成代码时,您需要调用 process.exit()。
回答by Abdullah Ayd?n
function fnAsyncTest(callback) {
require('fs').writeFile('async.txt', 'bye!', callback);
}
function fnSyncTest() {
for (var i = 0; i < 10; i++) {}
}
function killProcess() {
if (process.exitTimeoutId) {
return;
}
process.exitTimeoutId = setTimeout(() => process.exit, 5000);
console.log('process will exit in 5 seconds');
fnAsyncTest(function() {
console.log('async op. done', arguments);
});
if (!fnSyncTest()) {
console.log('sync op. done');
}
}
// https://nodejs.org/api/process.html#process_signal_events
process.on('SIGTERM', killProcess);
process.on('SIGINT', killProcess);
process.on('uncaughtException', function(e) {
console.log('[uncaughtException] app will be terminated: ', e.stack);
killProcess();
/**
* @https://nodejs.org/api/process.html#process_event_uncaughtexception
*
* 'uncaughtException' should be used to perform synchronous cleanup before shutting down the process.
* It is not safe to resume normal operation after 'uncaughtException'.
* If you do use it, restart your application after every unhandled exception!
*
* You have been warned.
*/
});
console.log('App is running...');
console.log('Try to press CTRL+C or SIGNAL the process with PID: ', process.pid);
process.stdin.resume();
// just for testing
回答by antongorodezkiy
Just wanted to mention deathpackage here: https://github.com/jprichardson/node-death
只想death在这里提一下包:https: //github.com/jprichardson/node-death
Example:
例子:
var ON_DEATH = require('death')({uncaughtException: true}); //this is intentionally ugly
ON_DEATH(function(signal, err) {
//clean up code here
})
回答by Golo Roden
io.jshas an exitand a beforeExitevent, which do what you want.
io.js有一个exit和一个beforeExit事件,可以做你想做的事。
回答by Mendel Hymans
Here's a nice hack for windows
这是一个很好的 Windows hack
process.on('exit', async () => {
require('fs').writeFileSync('./tmp.js', 'crash', 'utf-8')
});
回答by Jaime Gómez
In the case where the process was spawned by another node process, like:
如果该进程是由另一个节点进程产生的,例如:
var child = spawn('gulp', ['watch'], {
stdio: 'inherit',
});
And you try to kill it later, via:
然后您尝试通过以下方式杀死它:
child.kill();
This is how you handle the event [on the child]:
这是您处理事件的方式 [在孩子上]:
process.on('SIGTERM', function() {
console.log('Goodbye!');
});

