iT邦幫忙

DAY 32
4

node.js伺服器實戰系列 第 32

node.js伺服器實戰(-1) - 賽後亂搞dnode

dnode是一個node.js的rpc套件,拿來做出一些管理功能還不錯用。
需求

今天在http://www.facebook.com/groups/node.js.tw討論了一下不停止伺服器重新載入修改過模組的可能性,突然想到可以透過cluster與dnode做到。

cluster可以讓伺服器worker跑在子行程,並且在子行程結束時開啟新的子行程。透過這個方式,就可以重新啟動伺服器來載入更動過的程式,但是要遠端來控制還是會有一些困難。這時就要請dnode出馬。

https://github.com/substack/dnode

實作

稍微改過http://nodejs.org/docs/v0.6.0/api/cluster.html提供的官方範例,做出這個簡單的hello world伺服器(dcluster.js):

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
var dnode = require('dnode');


if (cluster.isMaster) {
   // Fork workers.
    var workers = [],i=0;
    for (var i = 0; i < numCPUs; i++) {
        workers.push(cluster.fork());
    }
    cluster.on('death', function(worker) {
        console.log('worker ' + worker.pid + ' died.');
        var i = 0;
        for(;i<workers.length; i++) {
            if(worker.pid === workers[i].pid) {
                workers.splice(i, 1);
            }
        }
        workers.push(cluster.fork());
    });
    var manager = dnode({
        restart: function(cb) {
            var i = 0;
            for(; i<workers.length; i++) {
                workers[i].send({cmd: 'close'});
                console.log('worker ('+workers[i].pid+') going to rebirth.');
            }
            cb('restart success');
        }
    });
    manager.listen(8000, 'localhost');

} else {
  // Worker processes have a http server.
    var msg = require('./message');
    var server = http.Server(function(req, res) {
        res.writeHead(200);
        res.end(msg.text);
    });
    server.listen(8443, 'localhost');
    process.on('message', function(msg) {
        if(msg && msg.cmd) {
            switch(msg.cmd) {
                case 'close':
                    process.nextTick(function(){
                        server.close();
                        process.exit();
                    });
                    break;
            }
        }
    });
}

這裡利用dnode寫了一個簡單的restart命令,在master收到這個命令後,會透過process.send對子行程送出訊息,格式是{cmd: 'close'}。子行程透過on message事件收到訊息後,就會自殺。接下來在cluster的on death事件中,會重新啟動一個子行程。

送出restart命令的程式非常簡單(dclient.js):

var dnode = require('dnode');

dnode.connect(8000, 'localhost',  function(remote) {
    remote.restart(function(str) {
        console.log(str);
        process.exit();
    });
});

另外,為了檢測重啟的子行程是否爭的可以載入新的模組,改寫一下res.end()送出的訊息,把它改成由message.js模組中載入:

module.exports = {
    text: 'hello world.\n'
};

使用node dcluster.js載入伺服器後,開啟瀏覽器打入網址http://localhost:8443/,就會看到**hello world.**訊息。接下來先修改message.js:

module.exports = {
    text: 'hello world too.\n'
};

然後執行node dclient.js命令伺服器重啟,這個時候在瀏覽器重新整理,就會看到訊息變成 hello world too. 。


上一篇
node.js伺服器實戰(31) - 結語
下一篇
node.js伺服器實戰(-2) - 賽後補完,做出plugin架構
系列文
node.js伺服器實戰33

1 則留言

0
shazi
iT邦新手 4 級 ‧ 2013-10-01 17:28:58

哇~~好文!!

我要留言

立即登入留言