fis-command-server
Advanced tools
Comparing version 0.7.0-beta4 to 0.7.0-beta5
@@ -69,4 +69,2 @@ var step = require('step'); | ||
var script = path.join(opt.root, 'server.js'); | ||
var logger = require('fs').createWriteStream(path.join(opt.root, 'server.log'), {flags: 'a'}); | ||
process.stdout.write('starting fis-server .'); | ||
@@ -110,3 +108,3 @@ var timeout = Math.max(opt.timeout * 1000, 5000); | ||
if (~chunk.indexOf('bind EADDRINUSE')) { | ||
if (~chunk.indexOf('EADDRINUSE')) { | ||
log = ''; | ||
@@ -137,5 +135,2 @@ errMsg = 'Address already in use:' + opt.port; | ||
server.stdout.pipe(logger); | ||
server.stderr.pipe(logger); | ||
server.stderr.on('data', onData); | ||
@@ -145,3 +140,2 @@ server.stdout.on('data', onData); | ||
server.on('error', function(err) { | ||
logger.write('\nGot Error: ' + err); | ||
try { | ||
@@ -156,4 +150,2 @@ process.kill(server.pid, 'SIGINT'); | ||
process.on('SIGINT', function(code) { | ||
logger.write('\nRecived an kill signal.'); | ||
try { | ||
@@ -163,2 +155,4 @@ process.kill(server.pid, 'SIGINT'); | ||
} catch(e){} | ||
process.exit(1); | ||
}); | ||
@@ -165,0 +159,0 @@ |
@@ -9,3 +9,4 @@ var util = require('../util.js'); | ||
exec: script, | ||
args: args | ||
args: args, | ||
respawn: true | ||
}); |
@@ -13,5 +13,4 @@ var path = require('path'); | ||
// 由于 windows 系统中 cluster.fork() 会弹出个新窗口,所以先不打算用 cluster 了,也不打算用多线程了,就开一个好了。 | ||
// 用 cluster 的好处是,可以让多个 worker 的服务可以监听同一个端口,这样便于挂在用户自己提供 server.js 文件,开端口没有限制。 | ||
// 用 cluster 的好处是,可以让多个 worker 的服务可以监听同一个端口,这样便于挂载用户自己提供 server.js 文件,同时开同一个端口没有限制。 | ||
if (process.platform === "win32") { | ||
var spawn = require('child_process').spawn; | ||
@@ -29,2 +28,3 @@ | ||
var execPath = process.execPath; | ||
var createProcess = function() { | ||
@@ -36,8 +36,19 @@ var argsRaw = process.argv.concat(); | ||
worker = spawn(process.execPath, argsRaw, { | ||
worker = spawn(execPath, argsRaw, { | ||
detached: true | ||
}); | ||
worker.on('exit', function() { | ||
logger.write('Worker %d died %s.', worker.pid, respawn ? " restarting" : ''); | ||
respawn && createProcess(); | ||
}); | ||
worker.stderr.on('data', function(chunk) { | ||
if (~chunk.toString().indexOf('Error')) { | ||
logger.write('Detected error, set `respawn` to false!'); | ||
respawn = false; | ||
} | ||
}); | ||
logger.write('Create a new worker %s.', worker.pid); | ||
logger.takecare(worker.stdout); | ||
@@ -48,3 +59,3 @@ logger.takecare(worker.stderr); | ||
// 为了让 lib/node.js 能够检测到服务器起来了。 | ||
worker.stdout.on('data', function(chunk) { | ||
isRuning || worker.stdout.on('data', function(chunk) { | ||
if (isRuning) { | ||
@@ -64,7 +75,2 @@ worker.stdout.removeListener('data', arguments.callee); | ||
worker.on('exit', function() { | ||
logger.write('The worker %s get killed.', worker.pid); | ||
respawn && createProcess(); | ||
}); | ||
return worker; | ||
@@ -74,5 +80,3 @@ } | ||
var killProcess = function(signal) { | ||
respawn = false; | ||
worker.kill('SIGTERM'); | ||
respawn = !!options.respawn; | ||
} | ||
@@ -82,34 +86,11 @@ | ||
process.on('SIGINT', function() { | ||
logger.write('QUIT received, will exit once all workers have finished current requests.'); | ||
function killSelf() { | ||
respawn = false; | ||
killProcess('SIGTERM'); | ||
}); | ||
logger.write('The master get killed!'); | ||
process.exit(); | ||
} | ||
process.on('SIGQUIT', function() { | ||
logger.write('QUIT received, will exit once all workers have finished current requests.'); | ||
killProcess('SIGTERM'); | ||
}); | ||
process.on('SIGTERM', killSelf); | ||
/** | ||
* Gracefully restarts the workers. | ||
*/ | ||
process.on('SIGHUP', function () { | ||
killProcess('SIGTERM'); | ||
killProcess('SIGTERM'); | ||
createProcess(); | ||
}); | ||
/** | ||
* Gracefully Shuts down the workers. | ||
*/ | ||
process.on('SIGTERM', function () { | ||
killProcess('SIGTERM'); | ||
}); | ||
process.on('exit', function() { | ||
logger.write('The main process get killed.'); | ||
killProcess('SIGTERM'); | ||
}); | ||
// watch server scripts modification, so we can gracefully restarts the server. | ||
@@ -165,3 +146,3 @@ if (options.watchFiles) { | ||
// 为了让 lib/node.js 能够检测到服务器起来了。 | ||
worker.process.stdout.on('data', function(chunk) { | ||
isRuning || worker.process.stdout.on('data', function(chunk) { | ||
if (isRuning) { | ||
@@ -183,5 +164,2 @@ worker.process.stdout.removeListener('data', arguments.callee); | ||
function killAllWorkers(signal) { | ||
// 避免自动重启。 | ||
respawn = false; | ||
logger.write('Kill all workers with signal `%s`', signal); | ||
@@ -195,5 +173,2 @@ | ||
} | ||
// 还原自动重启配置。 | ||
respawn = !!options.respawn; | ||
} | ||
@@ -226,28 +201,11 @@ | ||
process.on('SIGINT', function() { | ||
process.on('SIGTERM', function() { | ||
logger.write('QUIT received, will exit once all workers have finished current requests.'); | ||
respawn = false; | ||
killAllWorkers('SIGTERM'); | ||
}); | ||
process.on('SIGQUIT', function() { | ||
logger.write('QUIT received, will exit once all workers have finished current requests.'); | ||
killAllWorkers('SIGTERM'); | ||
// don't need to wait! | ||
process.exit(); | ||
}); | ||
/** | ||
* Gracefully restarts the workers. | ||
*/ | ||
process.on('SIGHUP', function () { | ||
killAllWorkers('SIGTERM'); | ||
createWorkers(workerCount); | ||
}); | ||
/** | ||
* Gracefully Shuts down the workers. | ||
*/ | ||
process.on('SIGTERM', function () { | ||
killAllWorkers('SIGTERM'); | ||
}); | ||
// watch server scripts modification, so we can gracefully restarts the server. | ||
@@ -263,3 +221,2 @@ if (options.watchFiles) { | ||
killAllWorkers('SIGTERM'); | ||
createWorkers(workerCount); | ||
}); | ||
@@ -275,7 +232,7 @@ } | ||
}; | ||
} | ||
var defaultOptions = module.exports.options = { | ||
watchFiles: null, | ||
workerCount: 0 | ||
}; | ||
} | ||
var defaultOptions = module.exports.options = { | ||
watchFiles: null, | ||
workerCount: 0 | ||
}; |
@@ -12,3 +12,7 @@ var fs = require('fs'); | ||
str = new Date() + ': ' + str + '\n'; | ||
this.writter.write(str); | ||
try { | ||
this.writter.write(str); | ||
} catch (e) { | ||
// | ||
} | ||
}; | ||
@@ -15,0 +19,0 @@ |
@@ -17,2 +17,9 @@ var express = require('express'); | ||
// 静态文件输出 | ||
app.use(express.static(DOCUMENT_ROOT, { | ||
index: ['index.html', 'index.htm', 'default.html', 'default.htm'], | ||
extensions: ['html', 'htm'] | ||
})); | ||
// 静态文件列表。 | ||
@@ -79,8 +86,2 @@ app.use((function() { | ||
// 静态文件输出 | ||
app.use(express.static(DOCUMENT_ROOT, { | ||
index: ['index.html', 'index.htm', 'default.html', 'default.htm'], | ||
extensions: ['html', 'htm'] | ||
})); | ||
// 错误捕获。 | ||
@@ -112,2 +113,3 @@ app.use(function(err, req, res, next) { | ||
process.disconnect && process.disconnect(); | ||
process.exit(0); | ||
} | ||
@@ -114,0 +116,0 @@ |
@@ -32,2 +32,41 @@ /** | ||
function checkPid(pid, opt, callback) { | ||
var list, msg = ''; | ||
var isWin = fis.util.isWin(); | ||
if (isWin) { | ||
list = spawn('tasklist'); | ||
} else { | ||
list = spawn('ps', ['-A']); | ||
} | ||
list.stdout.on('data', function (chunk) { | ||
msg += chunk.toString('utf-8').toLowerCase(); | ||
}); | ||
list.on('exit', function() { | ||
var found = false; | ||
msg.split(/[\r\n]+/).forEach(function(item){ | ||
var reg = new RegExp('\\b'+opt['process']+'\\b', 'i'); | ||
if (reg.test(item)) { | ||
var iMatch = item.match(/\d+/); | ||
if (iMatch && iMatch[0] == pid) { | ||
found = true; | ||
} | ||
} | ||
}); | ||
callback(found); | ||
}); | ||
list.on('error', function (e) { | ||
if (isWin) { | ||
fis.log.error('fail to execute `tasklist` command, please add your system path (eg: C:\\Windows\\system32, you should replace `C` with your system disk) in %PATH%'); | ||
} else { | ||
fis.log.error('fail to execute `ps` command.'); | ||
} | ||
}); | ||
} | ||
//server stop | ||
@@ -40,43 +79,44 @@ exports.stop = function(callback) { | ||
var pid = fis.util.fs.readFileSync(tmp, 'utf8').trim(); | ||
var list, msg = ''; | ||
var isWin = fis.util.isWin(); | ||
if (isWin) { | ||
list = spawn('tasklist'); | ||
} else { | ||
list = spawn('ps', ['-A']); | ||
} | ||
checkPid(pid, opt, function(exists) { | ||
if (exists) { | ||
// try to gracefully kill it. | ||
process.kill(pid, 'SIGTERM'); | ||
list.stdout.on('data', function (chunk) { | ||
msg += chunk.toString('utf-8').toLowerCase(); | ||
}); | ||
// checkout it every half second. | ||
(function(done) { | ||
var start = Date.now(); | ||
var timer = setTimeout(function() { | ||
var fn = arguments.callee; | ||
list.on('exit', function() { | ||
msg.split(/[\r\n]+/).forEach(function(item){ | ||
var reg = new RegExp('\\b'+opt['process']+'\\b', 'i'); | ||
if (reg.test(item)) { | ||
var iMatch = item.match(/\d+/); | ||
if (iMatch && iMatch[0] == pid) { | ||
try { | ||
process.kill(pid, 'SIGINT'); | ||
process.kill(pid, 'SIGKILL'); | ||
} catch (e) {} | ||
process.stdout.write('shutdown '+opt['process']+' process [' + iMatch[0] + ']\n'); | ||
} | ||
} | ||
}); | ||
fis.util.fs.unlinkSync(tmp); | ||
if (callback) { | ||
callback(opt); | ||
} | ||
}); | ||
list.on('error', function (e) { | ||
if (isWin) { | ||
fis.log.error('fail to execute `tasklist` command, please add your system path (eg: C:\\Windows\\system32, you should replace `C` with your system disk) in %PATH%'); | ||
checkPid(pid, opt, function(exists) { | ||
if (exists) { | ||
// 实在关不了,那就野蛮的关了它。 | ||
if (Date.now() - start > 5000) { | ||
try { | ||
process.kill(pid, 'SIGKILL'); | ||
} catch(e) { | ||
} | ||
clearTimeout(timer); | ||
done(); | ||
return; | ||
} | ||
timer = setTimeout(fn, 500); | ||
} else { | ||
done(); | ||
} | ||
}); | ||
}, 20); | ||
})(function() { | ||
process.stdout.write('shutdown '+opt['process']+' process [' + pid + ']\n'); | ||
fis.util.fs.unlinkSync(tmp); | ||
callback && callback(opt); | ||
}) | ||
} else { | ||
fis.log.error('fail to execute `ps` command.'); | ||
callback && callback(opt); | ||
} | ||
}); | ||
} else { | ||
@@ -83,0 +123,0 @@ if (callback) { |
{ | ||
"name": "fis-command-server", | ||
"description": "fis server command.", | ||
"version": "0.7.0-beta4", | ||
"version": "0.7.0-beta5", | ||
"author": "FIS Team <fis@baidu.com>", | ||
@@ -6,0 +6,0 @@ "homepage": "http://fis.baidu.com/", |
1012
10
4933266