Node.jsに、何らかの理由(Ctrl+ C、例外、またはその他の理由)で、終了する直前に常に何かを実行するように指示します。
私はこれを試しました:
process.on('exit', function (){
console.log('Goodbye!');
});
私はプロセスを始めて、それを殺しました、そして何も起こりませんでした。私はそれをもう一度始め、Ctrl+を押しましたCが、それでも何も起こりませんでした...
Node.jsに、何らかの理由(Ctrl+ C、例外、またはその他の理由)で、終了する直前に常に何かを実行するように指示します。
私はこれを試しました:
process.on('exit', function (){
console.log('Goodbye!');
});
私はプロセスを始めて、それを殺しました、そして何も起こりませんでした。私はそれをもう一度始め、Ctrl+を押しましたCが、それでも何も起こりませんでした...
回答:
ハンドラを登録して、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}));
must only実行することに注意してくださいsynchronousexit
beforeExit代わりにイベントを使用する必要があると思います。
stderr複数のクリーンアップハンドラ間で単一のメッセージを調整しません。私はこれをすべて行うモジュールgithub.com/jtlapp/node-cleanupを書きました。元は以下のcleanup.jsソリューションに基づいていますが、フィードバックに基づいて大幅に変更されています。お役に立てば幸いです。
以下のスクリプトでは、すべての終了条件に対して単一のハンドラーを使用できます。アプリ固有のコールバック関数を使用して、カスタムクリーンアップコードを実行します。
cleanup.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);
});
};
このコードは、キャッチされない例外、Ctrl+ Cおよび通常の終了イベントをインターセプトします。次に、終了する前に単一のオプションのユーザークリーンアップコールバック関数を呼び出し、単一のオブジェクトですべての終了条件を処理します。
このモジュールは、別のイベントエミッターを定義するのではなく、単にプロセスオブジェクトを拡張します。アプリ固有のコールバックがない場合、クリーンアップはデフォルトでno op関数になります。Ctrl+で終了するときに子プロセスを実行したままにしていた私の使用にはこれで十分でしたC。
必要に応じて、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
process.exit()。クリーンアップハンドラーは、終了コードまたはシグナルの関数として動作する柔軟性を備え、非同期クリーンアップをサポートしたり、周期的なクリーンアップを防止したりするために、必要に応じてクリーンアップハンドラーをアンインストールできます。これは、上記のコードにほとんど似ていません。
これは、処理できるすべての終了イベントをキャッチします。これまでのところ非常に信頼性が高く、クリーンなようです。
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`].forEach((eventType) => {
process.on(eventType, cleanUpServer.bind(null, eventType));
})
「exit」は、ノードが内部でイベントループを終了したときにトリガーされるイベントであり、外部でプロセスを終了したときにトリガーされません。
あなたが探しているのは、SIGINTで何かを実行することです。
http://nodejs.org/api/process.html#process_signal_eventsのドキュメントに例を示します。
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.');
});
注:これはsigintを中断するようで、コードを終了するときにprocess.exit()を呼び出す必要があります。
kill -2、SIGINTコードを渡します。ノードにtxtファイルへのロギングがあるため、Ctrl + Cを使用できないため、このようにする必要があります。
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
deathここでパッケージについて言及したかっただけです:https://github.com/jprichardson/node-death
例:
var ON_DEATH = require('death')({uncaughtException: true}); //this is intentionally ugly
ON_DEATH(function(signal, err) {
//clean up code here
})
io.jsにはexitとbeforeExitイベントがあり、必要な処理を実行します。
これがWindows用の素敵なハックです
process.on('exit', async () => {
require('fs').writeFileSync('./tmp.js', 'crash', 'utf-8')
});
他の答えで遊んだ後、これがこのタスクの私の解決策です。この方法を実装すると、クリーンアップを1か所に集中して、クリーンアップの二重処理を防ぐことができます。
const others = [`SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`]
others.forEach((eventType) => {
process.on(eventType, exitRouter.bind(null, { exit: true }));
})
function exitRouter(options, exitCode) {
if (exitCode || exitCode === 0) console.log(`ExitCode ${exitCode}`);
if (options.exit) process.exit();
}
function exitHandler(exitCode) {
console.log(`ExitCode ${exitCode}`);
console.log('Exiting finally...')
}
process.on('exit', exitHandler)
デモのために、これは私の要点へのリンクです。ファイルにsetTimeoutを追加して、実行中のプロセスを偽装します。
実行node node-exit-demo.jsして何もしない場合、2秒後にログが表示されます。
The service is finish after a while.
ExitCode 0
Exiting finally...
または、サービスが完了する前にで終了するとctrl+C、次のように表示されます。
^CExitCode SIGINT
ExitCode 0
Exiting finally...
何が起こったかというと、NodeプロセスはコードSIGINTで最初に終了し、次にprocess.exit()にルーティングされ、最後に終了コード0で終了しました。