エロサイトの作り方

2013年11月から勉強しながらエロサイトを作っています。

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);
    });
}