Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ $ eggctl start [options] [baseDir]
- `stdout` - customize stdout file, default to `$HOME/logs/master-stdout.log`.
- `stderr` - customize stderr file, default to `$HOME/logs/master-stderr.log`.
- `timeout` - the maximum timeout when app starts, default to 300s.
- `ignore-stderr` - whether ignore stderr when app starts.

### stop

Expand Down
78 changes: 47 additions & 31 deletions lib/cmd/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class StartCommand extends Command {
type: 'number',
default: 300 * 1000,
},
'ignore-stderr': {
description: 'whether ignore stderr when app starts',
type: 'boolean',
},
};
}

Expand All @@ -67,15 +71,16 @@ class StartCommand extends Command {
}

* run(context) {
const argv = Object.assign({}, context.argv);
const { argv, env, cwd, execArgv } = context;

const HOME = homedir();
const logDir = path.join(HOME, 'logs');

// egg-script start
// egg-script start ./server
// egg-script start /opt/app
let baseDir = argv._[0] || context.cwd;
if (!path.isAbsolute(baseDir)) baseDir = path.join(context.cwd, baseDir);
let baseDir = argv._[0] || cwd;
if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir);
argv.baseDir = baseDir;

const isDaemon = argv.daemon;
Expand All @@ -93,24 +98,18 @@ class StartCommand extends Command {
argv.stdout = argv.stdout || path.join(logDir, 'master-stdout.log');
argv.stderr = argv.stderr || path.join(logDir, 'master-stderr.log');

const env = context.env;
// normalize env
env.HOME = HOME;
env.NODE_ENV = 'production';

// adjust env for win
const currentPATH = env.PATH || env.Path;
// for nodeinstall
let newPATH = `${path.join(baseDir, 'node_modules/.bin')}${path.delimiter}`;
// support `${baseDir}/.node/bin`
const customNodeBinDir = path.join(baseDir, '.node/bin');
if (yield fs.exists(customNodeBinDir)) {
newPATH += `${customNodeBinDir}${path.delimiter}`;
}
if (currentPATH) {
env.PATH = `${newPATH}${currentPATH}`;
} else {
env.PATH = newPATH;
}
env.PATH = [
// for nodeinstall
path.join(baseDir, 'node_modules/.bin'),
// support `.node/bin`, due to npm5 will remove `node_modules/.bin`
path.join(baseDir, '.node/bin'),
// adjust env for win
env.PATH || env.Path,
].filter(x => !!x).join(path.delimiter);

// for alinode
env.ENABLE_NODE_LOG = 'YES';
Expand All @@ -121,24 +120,20 @@ class StartCommand extends Command {
if (argv.env) {
// if undefined, should not pass key due to `spwan`, https://github.com/nodejs/node/blob/master/lib/child_process.js#L470
env.EGG_SERVER_ENV = argv.env;
argv.env = undefined;
}

// remove unused properties, alias had been remove by `removeAlias`
argv._ = undefined;
argv.$0 = undefined;
argv.daemon = undefined;

const options = {
execArgv: context.execArgv,
execArgv,
env,
stdio: 'inherit',
detached: false,
};

this.logger.info('Starting %s application at %s', this.frameworkName, baseDir);

const eggArgs = [ this.serverBin, JSON.stringify(argv), `--title=${argv.title}` ];
// remove unused properties from stringify, alias had been remove by `removeAlias`
const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr' ];
const eggArgs = [ this.serverBin, stringify(argv, ignoreKeys), `--title=${argv.title}` ];
this.logger.info('Run node %s', eggArgs.join(' '));

// whether run in the background.
Expand All @@ -151,6 +146,7 @@ class StartCommand extends Command {
const child = this.child = spawn('node', eggArgs, options);
this.isReady = false;
child.on('message', msg => {
/* istanbul ignore else */
if (msg && msg.action === 'egg-ready') {
this.isReady = true;
this.logger.info('%s started on %s', this.frameworkName, msg.data.address);
Expand All @@ -177,25 +173,24 @@ class StartCommand extends Command {
let name = 'egg';
try {
const pkg = require(pkgPath);
/* istanbul ignore else */
if (pkg.name) name = pkg.name;
} catch (_) {
/* istanbul next */
}
return name;
}

* checkStatus({ stderr, timeout }) {
* checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) {
let count = 0;
let hasError = false;
let isSuccess = true;
timeout = timeout / 1000;
while (!this.isReady) {
try {
const stat = yield fs.stat(stderr);
if (stat && stat.size > 0) {
const [ stdout ] = yield exec('tail -n 100 ' + stderr);
this.logger.error(stdout);
this.logger.error('Start failed, see %s', stderr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里应该不用改吧,�只是根据参数判断 isSuccess 是否返回 true

Copy link
Member Author

@atian25 atian25 Dec 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个算是风格问题吧,感觉放到外面好点吧,while 里面只是循环 stat

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

主要这里有两个标志位,以后加逻辑比较容易错。

isSuccess = false;
hasError = true;
break;
}
} catch (_) {
Expand All @@ -212,6 +207,17 @@ class StartCommand extends Command {
this.logger.log('Wait Start: %d...', ++count);
}

if (hasError) {
try {
const [ stdout ] = yield exec('tail -n 100 ' + stderr);
this.logger.error(stdout);
} catch (_) {
// nothing
}
isSuccess = ignoreStdErr;
this.logger.error('Start got error, see %s', stderr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

随便改文案很容易把用例搞挂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

喔喔,忘记你们还继承了,下次注意

}

if (!isSuccess) {
this.child.kill('SIGTERM');
yield sleep(1000);
Expand All @@ -233,4 +239,14 @@ function* getRotatelog(logfile) {
return yield fs.open(logfile, 'a');
}

function stringify(obj, ignore) {
const result = {};
Object.keys(obj).forEach(key => {
if (!ignore.includes(key)) {
result[key] = obj[key];
}
});
return JSON.stringify(result);
}

module.exports = StartCommand;
16 changes: 15 additions & 1 deletion test/start.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,20 @@ describe('test/start.test.js', () => {
.end();
});

it('should status check fail `--ignore-stderr`, exit with 0', function* () {
mm(process.env, 'WAIT_TIME', 5000);
mm(process.env, 'ERROR', 'error message');

const stderr = path.join(homePath, 'logs/master-stderr.log');

yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--ignore-stderr' ], { cwd })
// .debug()
.expect('stderr', /nodejs.Error: error message/)
.expect('stderr', new RegExp(`Start got error, see ${stderr}`))
.expect('code', 0)
.end();
});

it('should status check fail, exit with 1', function* () {
mm(process.env, 'WAIT_TIME', 5000);
mm(process.env, 'ERROR', 'error message');
Expand All @@ -477,7 +491,7 @@ describe('test/start.test.js', () => {
yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd })
// .debug()
.expect('stderr', /nodejs.Error: error message/)
.expect('stderr', new RegExp(`Start failed, see ${stderr}`))
.expect('stderr', new RegExp(`Start got error, see ${stderr}`))
.expect('code', 1)
.end();
});
Expand Down