Node.jsでkillシグナルに対応したり、処理のタイムアウトを行ったりする
killシグナルへの対応
kill {pid}
コマンドなどでSIGTERM
が飛んで来た場合、
process.on('SIGTERM')
でキャッチできるようです。
この通知の中でprocess.exit()
すればプログラムが終了し、しなければ無視することができます。
ただしkill -9 {pid}
などでSIGKILL
を飛ばされると通知は来ないで問答無用で殺されます。
// killされたら、終了処理をして終わる
process.on('SIGTERM', function() {
console.log('SIGKILL Interupted.');
process.exit(1);
});
プログラムのタイムアウト
お馴染みのsetTimeout()
とclearTimeout()
を使って実装することになります。
// 30秒でタイムアウト
var handle = setTimeout(function() {
console.log('timeout.');
process.exit(1);
}, 30*1000);
// 実際には、なにか重たい処理
console.log('work begin.');
setTimeout(function() {
console.log('work end.');
}, workTime * 1000);
// 時間内に終了したらクリア
clearTimeout(handle);
特定のイベントループをタイムアウトするには?
実際には、プログラム自体を止めるというより、いわゆるスレッド単位で停止させたいという要望が多いと思うのですが、単純なやり方ではできなさそうです。
以下のようにcluster
を使うとできるのですが、これをループ処理と組み合わせて使うとなるとなかなか難しいですね。
'use strict';
var cluster = require('cluster');
var cpus = require('os').cpus();
if (cluster.isMaster) {
// マスター側の処理
console.log(process.pid, 'cluster begin.');
var timeout = process.argv[2];
// タイムアウト処理
var handle = setTimeout(function() {
// 処理が終わってないWorkerはkillする
for (var id in cluster.workers) {
var worker = cluster.workers[id];
console.log(worker.process.pid, 'worker timeout.');
worker.kill();
}
}, timeout * 1000);
// Workerの終了通知
cluster.on('exit', function() {
for (var id in cluster.workers) {
return;
}
// 全てのWorkerが終了
console.log(process.pid, 'cluster end.');
clearTimeout(handle);
});
// Worker作成
for (var i=0; i<cpus.length; i++) {
var worker = cluster.fork();
worker.send((i+1) * 3);
}
} else {
// Workerの処理
process.on('message', function(workTime) {
console.log(process.pid, 'worker begin.', workTime);
setTimeout(function() {
console.log(process.pid, 'worker end.');
process.exit(0);
}, workTime * 1000);
});
// マスター側からのkill通知
process.on('SIGINT', function() {
console.log(process.pid, 'worker killed.');
process.exit(0);
});
}