[master:35323][Mon Jul 02 2012 22:53:54 GMT+0800 (CST)] new worker forked (35324) as "/Users/mk2/git/node-cluster/test/fixtures/echo.js" [master:35323][Mon Jul 02 2012 22:53:54 GMT+0800 (CST)] new worker forked (35330) as "/Users/mk2/git/node-cluster/test/fixtures/echo.js" [master:35323][Mon Jul 02 2012 22:53:54 GMT+0800 (CST)] new worker forked (35336) as "/Users/mk2/git/node-cluster/test/fixtures/http.js" [master:35323][Mon Jul 02 2012 22:53:54 GMT+0800 (CST)] new worker forked (35337) as "/Users/mk2/git/node-cluster/test/fixtures/http.js" [unknown:35323][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] test log [mockname:35323][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] test log [worker:35323][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] direct listen at "80" Coverage

Coverage

92%
359
332
27

master.js

92%
230
212
18
LineHitsSource
1/* vim: set expandtab tabstop=2 shiftwidth=2 foldmethod=marker: */
2
32var fs = require('fs');
42var util = require('util');
52var Emitter = require('events').EventEmitter;
62var child_process = require('child_process');
7
82var common = require('./common');
92var STATUS = common.STATUS;
102var MESSAGE = common.MESSAGE;
112var debug = common.debug;
122var listen = common.listen;
132var MAX_HEARTBEAT_INTERVAL = common.MAX_HEARTBEAT_INTERVAL;
14
152var NOTICE = function (name, message) {
164 debug('master', Array.prototype.join.call(arguments, ' '));
17};
18
192var WRITE_STATUS_FILE = function (name, pid, message) {
20};
21
22/* {{{ private function _normalize() */
232var _normalize = function (name) {
245 return name.toString().trim().toLowerCase();
25};
26/* }}} */
27
282var _workerPair = function (argv, options, name) {
29
30 /**
31 * @ _options
32 */
333 var _options = {
34 'listen' : [],
35 'children' : require('os').cpus().length,
36 'max_request' : 0,
37 'max_fatal_restart': 5,
38 };
393 var groupName = name;
40
41 /* {{{ options rewrite */
42
433 for (var k in options) {
446 var value = options[k];
456 switch (k) {
46 case 'listen':
473 _options[k] = Array.isArray(value) ? value : [value];
483 break;
49 default:
503 _options[k] = value;
513 break;
52 }
53 }
54 /* }}} */
55
56 /**
57 * @ 请求队列
58 */
593 var _fdqueue = [];
60
61 /**
62 * @ 子进程列表
63 */
643 var _pobject = [];
65
66 /**
67 * @ 子进程状态
68 */
693 var _pstatus = {};
70
713 var _killall = function (signal) {
726 _pobject.forEach(function (sub) {
7312 try {
7412 sub.kill(signal || 'SIGTERM');
75 } catch (e) {
76 }
77 });
786 _pobject = [];
79 };
80
81 /**
82 * @ fatal restarts
83 */
843 var _fatals = [];
85
86 /* {{{ function _newChild() */
87 /**
88 * fork a new child process
89 * @return {Object} child_process
90 */
913 var _command = argv.join(' ');
923 var _execpath = argv.shift();
933 var _newChild = function () {
94
9534 var sub = child_process.fork(_execpath, argv, {
96 'cwd' : process.cwd(),
97 'env' : process.env,
98 });
9934 var pid = sub.pid;
100
10134 _pobject.push(sub);
10234 _pstatus[pid] = {
103 'status' : STATUS.UNKNOWN,
104 };
105
10634 NOTICE(util.format('new worker forked (%d) as "%s"', pid, _command));
107
108 /**
109 * @ on exit
110 */
111 /* {{{ */
11234 sub.on('exit', function (code, signal) {
11316 var _objects = [];
11416 _pobject.forEach(function (item) {
11569 if (item.pid !== pid) {
11655 _objects.push(item);
117 }
118 });
11916 _pobject = _objects;
12016 delete _pstatus[pid];
121
12216 if (STATUS.STOPING === _wstatus) {
1232 return;
124 }
125
12614 if (code && 'SIGKILL' !== signal) {
1276 var now = Date.now();
1286 if (_fatals.unshift(now) > _options.max_fatal_restart) {
1291 _fatals = _fatals.slice(0, _options.max_fatal_restart);
130 }
131
1326 if (_fatals.length >= _options.max_fatal_restart && _fatals[_fatals.length - 1] + 60000 >= now) {
1332 NOTICE('max fatal restarts (' + _options.max_fatal_restart + ') arrived, give up to fork');
134
1352 __GLOBAL_MASTER.emit('giveup', groupName, _fatals.length);
136 // after 1 minute, start again
1372 setTimeout(function () {
1380 _me.start();
139 }, 60100);
140
1412 return;
142 }
143 }
14412 _me.start();
145 });
146 /* }}} */
147
148 /**
149 * @on message
150 */
151 /* {{{ */
15234 var _send = function (type, data, handle, port) {
1536 try {
1546 sub.send({
155 'type' : type,
156 'data' : data,
157 'port' : port
158 }, handle);
159 } catch (e) {
1600 NOTICE('SEND', e.stack);
161 }
162 };
163
16434 sub.on('message', function (msg) {
16543 if (!msg || !msg.type) {
16616 return;
167 }
168
16927 switch (msg.type) {
170 case MESSAGE.GET_FD:
1716 var _item = _fdqueue.shift();
1726 if (!_item) {
1732 _send(MESSAGE.REQ_FD, 0);
1742 break;
175 }
1764 var _fd = _item[1];
1774 _send(MESSAGE.REQ_FD, _fdqueue.length, _fd, _item[0]);
1784 _fd.close();
1794 _fd = null;
1804 break;
181
182 case MESSAGE.STATUS:
18313 var pstat = _pstatus[pid] = msg.data;
18413 pstat._time = Date.now();
18513 WRITE_STATUS_FILE(groupName, pid, pstat);
18613 _check_stat_change();
18713 if (_options.max_request && pstat.scores > _options.max_request) {
1884 _newChild();
1894 _tobekill.push(pid);
190 }
19113 break;
192
193 case MESSAGE.RELOAD:
1941 if (msg.data) {
1951 var gname = _normalize(msg.data.name || groupName);
1961 if (__WORKERS_LIST[gname]) {
1971 __WORKERS_LIST[gname].reload();
198 }
199 }
2001 break;
201
202 case MESSAGE.SENDTO:
2033 if (msg.data && msg.data.name && msg.data.data) {
2041 var gname = _normalize(msg.data.name);
2051 if (__WORKERS_LIST[gname]) {
206 // TODO: gname or groupName?
2071 __WORKERS_LIST[gname].accept(msg.data.data, groupName, pid);
208 }
209 }
2103 break;
211
212 default:
2134 break;
214 }
215 });
216 /* }}} */
217
21834 return sub;
219
220 };
221 /* }}} */
222
2233 var _running = 0;
224
225 /* {{{ */
2263 var _check_stat_change = function () {
22713 var _floor = _options.children / 2;
22813 var _count = 0;
22913 for (var i in _pstatus) {
23053 var _stat = _pstatus[i];
23153 if (STATUS.RUNNING === _stat.status /** && _stat._time >= ? */) {
23231 _count++;
233 }
234 }
23513 if (_count !== _running) {
2369 __GLOBAL_MASTER.emit('state', groupName, _count, _running);
237 }
238
23913 _running = _count;
24013 if (_running >= _floor) {
24112 _tobekill.forEach(function (pid) {
2428 process.kill(pid, 'SIGTERM');
243 });
24412 _tobekill = [];
245 }
246 };
247 /* }}} */
248
249 /**
250 * @process object
251 */
2523 var _wakeups = 0;
253
254 /**
255 * @to be killed process
256 */
2573 var _tobekill = [];
258
259 /**
260 * @listeners
261 */
2623 var _listener = {};
263
264 /**
265 * @worker status
266 */
2673 var _wstatus = STATUS.PENDING;
268
269 /**
270 * @timer to check heartbeat
271 */
272 /* {{{ */
2733 var _timer = setInterval(function () {
2740 var _expire = Date.now() - MAX_HEARTBEAT_INTERVAL;
2750 for (var pid in _pstatus) {
2760 var _stat = _pstatus[pid];
277 // `MAX_HEARTBEAT_INTERVAL` no heartbeat, kill the worker
2780 if (_stat._time < _expire) {
2790 _newChild();
2800 _tobekill.push(pid);
281 }
282 }
283 }, 2000);
284
285 /* }}} */
286
2873 var _me = {};
288
289 /* {{{ public function start() */
2903 _me.start = function () {
29116 _wstatus = STATUS.PENDING;
29216 for (var i = _pobject.length; i < _options.children; i++) {
29311 _newChild();
294 }
295
29616 var usepush = 2 * _options.children;
29716 _options.listen.forEach(function (item) {
29817 if (_listener[item]) {
29913 return;
300 }
3014 _listener[item] = listen(item, function (handle, port) {
3024 if (_fdqueue.push([port, handle]) <= usepush) {
3034 _wakeups = (_wakeups + 1) % _pobject.length;
3044 try {
3054 _pobject[_wakeups].send({
306 'type' : MESSAGE.WAKEUP,
307 });
308 } catch (e) {
309 }
310 }
311 });
312 });
313 };
3143 _me.start();
315 /* }}} */
316
317 /* {{{ public function stop() */
318 /**
319 * stop worker process
320 */
3213 _me.stop = function (callback, signal) {
3226 _wstatus = STATUS.STOPING;
3236 for (var idx in _listener) {
3244 var _fd = _listener[idx];
3254 _fd.close();
3264 _fd = null;
327 }
3286 _listener = {};
3296 _killall(signal);
330
3316 callback && callback();
332
333 // var _timer1, _timer2;
334 // _timer1 = setTimeout(function () {
335 // _killall(signal);
336 // clearInterval(_timer2);
337 // }, 1000);
338
339 // _timer2 = setInterval(function () {
340 // if (0 === _fdqueue.length) {
341 // _killall(signal);
342 // clearTimeout(_timer1);
343 // clearInterval(_timer2);
344 // }
345 // }, 20);
346 };
347 /* }}} */
348
349 /* {{{ public function reload() */
3503 _me.reload = function () {
3515 for (var pid in _pstatus) {
35219 _newChild();
35319 pid = parseInt(pid, 10);
35419 if (pid) {
35519 _tobekill.push(pid);
356 }
357 }
358 };
359 /* }}} */
360
361 /* {{{ public function accept() */
3623 _me.accept = function (data, from, pid) {
3631 _pobject.forEach(function (sub) {
3644 try {
3654 sub.send({
366 'type' : MESSAGE.COMMAND,
367 'data' : data,
368 'from' : from,
369 'pid' : pid,
370 });
371 } catch (e) {
3720 NOTICE('SEND', e.stack);
373 }
374 });
375 };
376 /* }}} */
377
3783 return _me;
379
380};
381
382/* {{{ function _createPidFile() */
3832var _createPidFile = function (fname) {
3842 var pid = String(process.pid);
3852 fs.writeFile(fname, pid, function (error) {
3862 if (error) {
3870 throw error;
388 }
389 });
390
3912 process.on('exit', function () {
3920 try {
3930 if (pid !== fs.readFileSync(fname, 'utf-8').trim()) {
3940 return;
395 }
3960 fs.unlinkSync(fname);
397 } catch (e) {
398 }
399 });
400};
401/* }}} */
402
403/* {{{ Master constructor */
404
4052var Master = function (options) {
4062 if (!(this instanceof Master)) {
4070 return new Master();
408 }
409
4102 if (options.pidfile) {
4112 _createPidFile(options.pidfile);
412 }
413
4142 if (options.statusfile) {
4152 WRITE_STATUS_FILE = function (name, pid, message) {
41613 fs.createWriteStream(options.statusfile, {
417 flags: 'a+',
418 encoding: 'utf-8',
419 mode: 0644
420 }).end(util.format(
421 '%d:\t%s\t%d\t%j\n', process.pid, name, pid, message
422 ));
423 };
424
425 // XXX: fork
426 }
427
4282 Emitter.call(this);
429};
4302util.inherits(Master, Emitter);
431
432/* }}} */
433
4342var __WORKERS_LIST = {};
4352var __GLOBAL_MASTER = null;
436
437/**
438 * Register a group of workers.
439 * @param {String} name
440 * @param {String} file, worker file path.
441 * @param {Object} options
442 * - {Array|Number|String} listen, listen port or domain sock, e.g.: `80`, `[80, 8080]` or `[80, '/tmp/web.sock']`.
443 * - {Number} [children], worker number, default is `os.cpu` number.
444 * - {Number} [max_request], max request number per child worker. Dafault is `0`, no limit.
445 * - {Number} [max_fatal_restart], max fatal to giveup restart. Dafault is `5`.
446 * - {Bool} [trace_gc], trace gc, default is `false`.
447 * @param {Array} [argv] process start argv.
448 * @api public
449 */
4502Master.prototype.register = function (name, file, options, argv) {
4513 name = _normalize(name);
4523 if (__WORKERS_LIST[name]) {
4530 __WORKERS_LIST[name].stop(function () {
454 }, 'SIGKILL');
455 }
456
4573 argv = Array.isArray(argv) ? argv : [];
4583 argv.unshift(file);
459
4603 if (options.trace_gc) {
4610 argv.unshift('--trace_gc');
4620 delete options.trace_gc;
463 }
464
4653 __WORKERS_LIST[name] = _workerPair(argv, options, name);
4663 return this;
467};
468
4692Master.prototype.shutdown = function (callback, signal, name) {
4707 if (name) {
4714 if (__WORKERS_LIST[name]) {
4723 __WORKERS_LIST[name].stop(callback, signal);
473 } else {
4741 callback && callback();
475 }
476 } else {
4773 for (var k in __WORKERS_LIST) {
4783 __WORKERS_LIST[k].stop(null, signal);
479 }
4803 callback && callback();
481 }
4827 return this;
483};
484
4852Master.prototype.reload = function (name) {
4864 if (name) {
4872 if (__WORKERS_LIST[name]) {
4882 __WORKERS_LIST[name].reload();
489 }
490 } else {
4912 for (var k in __WORKERS_LIST) {
4922 __WORKERS_LIST[k].reload();
493 }
494 }
4954 return this;
496};
497
4982Master.prototype.dispatch = function () {
4991 for (var name in __WORKERS_LIST) {
5001 __WORKERS_LIST[name].start();
501 }
5021 return this;
503};
504
5052exports.create = function (options) {
506
5073 if (!__GLOBAL_MASTER) {
5082 __GLOBAL_MASTER = new Master(options);
509
5102 process.on('SIGHUB', function () {});
5112 process.on('exit', function () {
5121 NOTICE('About to exit ...');
5131 __GLOBAL_MASTER.shutdown(function () {
5141 NOTICE('SIGKILL exited');
515 }, 'SIGKILL');
516 });
517
5182 process.on('SIGTERM', function () {
5191 NOTICE('Got SIGTERM, about to exit...');
5201 __GLOBAL_MASTER.shutdown(function () {
5211 NOTICE('SIGTERM exited');
522 });
523 });
524
5252 process.on('SIGUSR1', function () {
5261 NOTICE('Got SIGUSR1, about to reload...');
5271 __GLOBAL_MASTER.reload();
528 });
529 }
530
5313 return __GLOBAL_MASTER;
532
533};
534

common.js

100%
31
31
0
LineHitsSource
1/* vim: set expandtab tabstop=2 shiftwidth=2 foldmethod=marker: */
2
32exports.MAX_HEARTBEAT_INTERVAL = 30000;
4
5/**
6 * @&#232;&#191;&#155;&#231;&#168;&#139;&#231;&#138;&#182;&#230;&#128;&#129;&#230;&#156;&#186;
7 */
82exports.STATUS = {
9 'UNKNOWN' : 0, /**< &#230;&#156;&#170;&#231;&#159;&#165;&#231;&#138;&#182;&#230;&#128;&#129; */
10 'PENDING' : 1, /**< &#229;&#135;&#134;&#229;&#164;&#135;&#231;&#138;&#182;&#230;&#128;&#129; */
11 'RUNNING' : 2, /**< &#229;&#143;&#175;&#230;&#142;&#165;&#229;&#143;&#151;&#230;&#156;&#141;&#229;&#138;&#161; */
12 'STOPING' : 3, /**< &#229;&#135;&#134;&#229;&#164;&#135;&#229;&#133;&#179;&#233;&#151;&#173; */
13};
14
15/**
16 * @&#230;&#182;&#136;&#230;&#129;&#175;&#231;&#177;&#187;&#229;&#158;&#139;
17 */
182exports.MESSAGE = {
19 'GET_FD' : 11, /**< &#232;&#142;&#183;&#229;&#143;&#150;&#229;&#143;&#165;&#230;&#159;&#132; (worker -> master) */
20 'REQ_FD' : 12, /**< &#232;&#175;&#183;&#230;&#177;&#130;&#229;&#143;&#165;&#230;&#159;&#132; (master -> worker) */
21 'WAKEUP' : 14, /**< &#229;&#148;&#164;&#233;&#134;&#146;&#230;&#182;&#136;&#230;&#129;&#175; (master -> worker) */
22 'LISTEN' : 16, /**< &#231;&#155;&#145;&#229;&#144;&#172;&#231;&#171;&#175;&#229;&#143;&#163; (master -> worker) */
23 'STATUS' : 21, /**< &#231;&#138;&#182;&#230;&#128;&#129;&#230;&#138;&#165;&#229;&#145;&#138; (worker -> master) */
24 'RELOAD' : 23, /**< &#233;&#135;&#141;&#232;&#189;&#189;&#232;&#191;&#155;&#231;&#168;&#139; (worker -> master) */
25 'SENDTO' : 31, /**< &#232;&#189;&#172;&#229;&#143;&#145;&#230;&#182;&#136;&#230;&#129;&#175; (worker -> master) */
26 'COMMAND' : 32, /**< &#229;&#145;&#189;&#228;&#187;&#164;&#230;&#182;&#136;&#230;&#129;&#175; (master -> worker) */
27};
28
29/**
30 * @&#230;&#137;&#147;&#229;&#141;&#176;&#230;&#151;&#165;&#229;&#191;&#151;
31 */
322exports.debug = function (name, message) {
337 console.log('[' + (name || 'unknown') + ':' + process.pid + '][' + new Date() + '] ' + message);
34};
35
36/**
37 * @&#231;&#155;&#145;&#229;&#144;&#172;&#231;&#171;&#175;&#229;&#143;&#163;&#230;&#136;&#150;&#232;&#128;&#133;socket
38 */
39/* {{{ public function listen() */
40
412var __tcpError = function (name, message) {
423 var error = new Error(message || 'unknown');
433 error.name = name;
443 return error;
45};
46
472var TCP = process.binding('tcp_wrap').TCP;
482var Pipe = process.binding('pipe_wrap').Pipe;
492exports.listen = function (portOrSock, connection) {
5010 portOrSock = /^\d+$/.test(portOrSock) ? Number(portOrSock) : portOrSock;
5110 var _me;
5210 var ret;
5310 if (typeof portOrSock === 'number') {
547 _me = new TCP();
557 ret = _me.bind('0.0.0.0', portOrSock);
56 } else {
573 _me = new Pipe();
583 ret = _me.bind(portOrSock);
59 }
60
6110 if (ret) {
62 // if `ret` is not zero, bind error.
632 _me.close();
642 _me = null;
652 throw __tcpError('BIND', 'Can not bind to ' + portOrSock);
66 }
67
688 if (_me.listen(1023)) {
691 _me.close();
701 _me = null;
711 throw __tcpError('LISTEN', 'Can not listen at ' + portOrSock);
72 }
73
747 _me.onconnection = function (handle) {
757 connection(handle, portOrSock);
76 };
77
787 return _me;
79};
80/* }}} */
81

worker.js

90%
98
89
9
LineHitsSource
1/* vim: set expandtab tabstop=2 shiftwidth=2 foldmethod=marker: */
2
32var Socket = require('net').Socket;
4
52var common = require('./common');
62var listen = common.listen;
72var debug = common.debug;
82var STATUS = common.STATUS;
92var MESSAGE = common.MESSAGE;
102var MAX_HEARTBEAT_INTERVAL = common.MAX_HEARTBEAT_INTERVAL;
112var arrayJoin = Array.prototype.join;
12
132var NOTICE = function (name, message) {
141 debug('worker', arrayJoin.call(arguments, ' '));
15};
16
17/* {{{ private function _send() */
18/**
19 * &#229;&#144;&#145;&#231;&#136;&#182;&#232;&#191;&#155;&#231;&#168;&#139;&#229;&#143;&#145;&#233;&#128;&#129;&#230;&#182;&#136;&#230;&#129;&#175;
20 *
21 * @access private
22 * @param {Number} type: see MESSAGE
23 * @param {Object} data
24 */
252if (!process.hasOwnProperty('send')) {
262 var _send = function (type, data) {
270 NOTICE('_SEND', JSON.stringify({
28 'type' : type,
29 'data' : data,
30 }));
31 };
32} else {
330 var _send = function (type, data) {
340 try {
350 process.send({
36 'type' : type,
37 'data' : data,
38 });
39 } catch (e) {
400 NOTICE('ERROR', e.stack);
410 process.exit(0);
42 }
43 };
44}
45/* }}} */
46
47/* {{{ private function _accept() */
482var _accept = function (handle, port, callback) {
496 if (!handle) {
501 return;
51 }
525 if (!callback) {
531 handle.close();
541 handle = null;
551 return;
56 }
57
584 var _me = new Socket({
59 'handle' : handle,
60 });
61
624 _me.readable = true;
634 _me.writable = true;
644 _me.resume();
654 _me.on('error', function (error) {
660 NOTICE('SOCKET', error.stack);
67 });
684 _me.emit('connect');
694 callback(_me, port);
70};
71/* }}} */
72
732exports.create = function (options) {
74
752 var _me = {};
76
77 /* {{{ &#230;&#142;&#167;&#229;&#136;&#182;&#229;&#143;&#130;&#230;&#149;&#176; */
78
792 var _conf = {};
802 options = options || {};
812 _conf.heartbeat_interval = parseInt(options.heartbeat_interval, 10) || 2000;
822 _conf.terminate_timeout = parseInt(options.terminate_timeout, 10) || 1000;
832 if (_conf.heartbeat_interval > MAX_HEARTBEAT_INTERVAL) {
841 _conf.heartbeat_interval = MAX_HEARTBEAT_INTERVAL;
85 }
86 /* }}} */
87
88 /**
89 * @&#229;&#191;&#131;&#232;&#183;&#179;&#230;&#149;&#176;&#230;&#141;&#174;
90 */
912 var mstat = {
92 'status' : STATUS.PENDING,
93 'scores' : 0,
94 };
95
96 /**
97 * @&#229;&#133;&#182;&#228;&#187;&#150;worker&#229;&#143;&#145;&#230;&#157;&#165;&#231;&#154;&#132;&#230;&#182;&#136;&#230;&#129;&#175;&#229;&#164;&#132;&#231;&#144;&#134;&#229;&#135;&#189;&#230;&#149;&#176;
98 */
992 var onmsg = [];
100
101 /**
102 * @worker&#231;&#155;&#180;&#229;&#144;&#172;&#230;&#168;&#161;&#229;&#188;&#143;
103 */
1042 var _listener = {};
105
106 /* {{{ &#229;&#191;&#131;&#232;&#183;&#179;&#230;&#150;&#185;&#230;&#179;&#149; */
107
1082 var heartbeat = function () {
1091 mstat.mem = process.memoryUsage();
1101 _send(MESSAGE.STATUS, mstat);
111 };
112
113 /* }}} */
114
115 /* {{{ &#228;&#191;&#161;&#229;&#143;&#183;&#229;&#164;&#132;&#231;&#144;&#134; */
116
1172 process.on('SIGHUB', function () {});
1182 process.on('SIGTERM', function () {
1191 mstat.status = STATUS.STOPING;
1201 for (var idx in _listener) {
1211 var _fd = _listener[idx];
1221 _fd.close();
1231 _fd = null;
124 }
1251 _listener = {};
126
1271 setTimeout(function () {
1280 process.exit(0);
129 }, _conf.terminate_timeout);
130 });
1312 process.on('exit', function () {
1320 NOTICE('terminated after ' + Number(process.uptime()).toFixed(3) + ' seconds.');
133 });
134
135 /* }}} */
136
137 /* {{{ public function ready() */
138 /**
139 * worker&#232;&#191;&#155;&#229;&#133;&#165;&#232;&#191;&#144;&#232;&#161;&#140;&#231;&#138;&#182;&#230;&#128;&#129;
140 */
1412 _me.ready = function (callback) {
1421 mstat = {
143 'status' : STATUS.RUNNING,
144 'scores' : 0,
145 };
1461 heartbeat();
1471 setInterval(heartbeat, _conf.heartbeat_interval);
148
1491 process.on('message', function (msg, handle) {
1509 if (!msg || !msg.type) {
1513 return;
152 }
153
1546 switch (msg.type) {
155 case MESSAGE.WAKEUP:
1561 if (STATUS.RUNNING === mstat.status) {
1571 _send(MESSAGE.GET_FD);
158 }
1591 break;
160
161 case MESSAGE.REQ_FD:
1622 mstat.scores++;
1632 _accept(handle, msg.port, callback);
1642 if (STATUS.RUNNING === mstat.status && msg.data) {
1651 process.nextTick(function () {
1661 _send(MESSAGE.GET_FD);
167 });
168 }
1692 break;
170
171 case MESSAGE.LISTEN:
1721 var _addr = msg.data;
1731 if (_addr && !_listener[_addr]) {
1741 _listener[_addr] = listen(_addr, function (handle, port) {
1751 mstat.scores++;
1761 _accept(handle, port, callback);
177 });
1781 NOTICE('direct listen at "' + _addr + '"');
179 }
1801 break;
181
182 case MESSAGE.COMMAND:
1831 onmsg.forEach(function (cb) {
1841 if (cb && msg.data) {
1851 cb(msg.data, msg.from, msg.pid);
186 }
187 });
1881 break;
189
190 default:
1911 break;
192 }
193 });
194
1951 return _me;
196 };
197 /* }}} */
198
199 /* {{{ public function onmessage() */
200 /**
201 * &#230;&#182;&#136;&#230;&#129;&#175;&#229;&#164;&#132;&#231;&#144;&#134;&#229;&#135;&#189;&#230;&#149;&#176;
202 *
203 * @access public
204 */
2052 _me.onmessage = function (cb) {
2062 if (!cb) {
2071 onmsg = [];
208 } else {
2091 onmsg.push(cb);
210 }
211 };
212 /* }}} */
213
214 /* {{{ public function sendto() */
215 /**
216 * &#229;&#144;&#145;&#229;&#133;&#182;&#228;&#187;&#150;&#232;&#191;&#155;&#231;&#168;&#139;&#229;&#143;&#145;&#233;&#128;&#129;&#230;&#182;&#136;&#230;&#129;&#175;
217 *
218 * @access public
219 * @param {String} who, process name
220 * @param {Object} data
221 */
2222 _me.sendto = function (who, data) {
2231 _send(MESSAGE.SENDTO, {
224 'name' : who,
225 'data' : data,
226 });
227 };
228 /* }}} */
229
230 /* {{{ public function reload() */
231 /**
232 * reload&#229;&#133;&#182;&#228;&#187;&#150;&#232;&#191;&#155;&#231;&#168;&#139;
233 *
234 * @access public
235 * @param {String} who, process name
236 */
2372 _me.reload = function (who) {
2381 _send(MESSAGE.RELOAD, {
239 'name' : who,
240 });
241 };
242 /* }}} */
243
2442 return _me;
245
246};
[master:35323][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] About to exit ... [master:35323][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] SIGKILL exited [worker:35337][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] terminated after 1.000 seconds. [worker:35336][Mon Jul 02 2012 22:53:55 GMT+0800 (CST)] terminated after 1.000 seconds.