Skip to content
This repository was archived by the owner on May 30, 2019. It is now read-only.

Commit a5bda10

Browse files
committed
e2e: proactively/fully close child processes on e2e exit
On process exit for e2e task, use brute force to kill java process (using tree-kill module on windows an process.exit on other platforms). Track closure of child processes more completely and correctly. Give java up to 5 seconds to shut down before giving up on it. Closes #669
1 parent 79bbec0 commit a5bda10

File tree

8 files changed

+190
-96
lines changed

8 files changed

+190
-96
lines changed

npm-shrinkwrap.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"supertest": "^0.15.0",
8282
"through2": "^0.6.3",
8383
"tiny-lr-fork": "^0.0.5",
84+
"tree-kill": "0.0.6",
8485
"vinyl-buffer": "1.0.0",
8586
"vinyl-fs": "^1.0.0",
8687
"yargs": "^3.4.5"

shared/js/dev-tasks/context.js

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,24 @@ var closeServer = function (server, cb) {
146146
}
147147
};
148148
try {
149-
server.on('end', onClosed);
150-
server.on('close', onClosed);
151-
server.on('exit', onClosed);
149+
if (server.on) {
150+
// a standard node process
151+
server.on('end', onClosed);
152+
server.on('close', onClosed);
153+
server.on('exit', onClosed);
154+
}
152155
if (server.close) {
156+
// a manually managed process of ours
153157
server.close(onClosed);
154158
}
155159
else {
156-
server.kill();
160+
if (server.kill) {
161+
server.kill();
162+
}
163+
else {
164+
// this isn't really an external process
165+
cb();
166+
}
157167
}
158168
}
159169
catch (err) {
@@ -255,6 +265,10 @@ self = module.exports = {
255265
// server in activeServers (and thus attempt close them all in parallel)
256266
_.map(activeServers, function (server, key) {
257267
return function (cb) {
268+
var waitTime = 1000;
269+
if (key === 'middle-tier') {
270+
waitTime = 5000; //java is slow to exit
271+
}
258272
$.util.log(chalk.green('shutting down ' + key));
259273
var closed = false;
260274
setTimeout(function () {
@@ -267,7 +281,7 @@ self = module.exports = {
267281
}
268282
catch (err) { console.log(err); }
269283
}
270-
}, 1000);
284+
}, waitTime);
271285
closeServer(
272286
server,
273287
function (err) {
@@ -376,7 +390,7 @@ self = module.exports = {
376390
listener.on('error', function (err) {
377391
console.log(err);
378392
});
379-
self.setActiveServer(port, server);
393+
self.setActiveServer(port, listener);
380394

381395
return server;
382396
}

shared/js/dev-tasks/e2e/middleTierJava.js

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ var $ = helper.$;
2323
var ctx = require('../context');
2424
var options = ctx.options;
2525

26-
var shell = require('shelljs');
27-
2826
var childProcess = require('child_process');
2927
var chalk = require('chalk');
3028
var gradleCmd = /^win/.test(process.platform) ? 'gradlew.bat' : './gradlew';
@@ -34,13 +32,18 @@ var customSeed = require('yargs').argv.seed;
3432

3533
var shellCmd = function (cwd, command, signal, cb) {
3634
process.stdout.write(chalk.green('\n' + command + '\n'));
37-
var backupWd = process.cwd();
38-
process.chdir(cwd);
39-
var child = shell.exec(command, { async: true, silent: true });
40-
process.chdir(backupWd);
35+
// var backupWd = process.cwd();
36+
// process.chdir(cwd);
37+
var commandSplit = command.split(' ');
38+
var child = childProcess.spawn(
39+
commandSplit[0],
40+
commandSplit.slice(1),
41+
{ cwd: cwd }
42+
);
43+
4144
if (signal) {
4245
process.on('exit', function () {
43-
child.kill();
46+
require('tree-kill')(child.pid, 'SIGKILL');
4447
});
4548
}
4649

@@ -64,9 +67,9 @@ var shellCmd = function (cwd, command, signal, cb) {
6467
var message = '';
6568
outBuff += data;
6669
if (outBuff.indexOf('\n') > -1) {
67-
message = outBuff.substr(0, outBuff.indexOf('\n') + 1);
68-
outBuff = outBuff.substr(outBuff.indexOf('\n') + 1);
69-
if (!signaled && signal && data.indexOf(signal) > -1) {
70+
message = outBuff.substr(0, outBuff.toString().indexOf('\n') + 1);
71+
outBuff = outBuff.substr(outBuff.toString().indexOf('\n') + 1);
72+
if (!signaled && signal && data.toString().indexOf(signal) > -1) {
7073
signaled = true;
7174
return cb(null, child);
7275
}
@@ -83,11 +86,12 @@ var shellCmd = function (cwd, command, signal, cb) {
8386

8487
child.stderr.on('data', function (data) {
8588
if (!signaled) {
86-
process.stdout.write(chalk.red('\n' + data.trim()));
89+
process.stdout.write(chalk.red('\n' + data.toString().trim()));
8790
}
8891
});
8992
};
9093

94+
var mtServer;
9195

9296
var pokeServer = function (cb) {
9397
var request = require('request');
@@ -98,10 +102,29 @@ var pokeServer = function (cb) {
98102
);
99103
};
100104

105+
var closeServer = function (cb) {
106+
var streamClosedCount = 0;
107+
108+
var streamOnClosed = function () {
109+
if (++streamClosedCount === 2) {
110+
cb();
111+
}
112+
};
113+
114+
mtServer.stdout.on('close', streamOnClosed);
115+
mtServer.stderr.on('close', streamOnClosed);
116+
117+
if (process.platform === 'win32') {
118+
require('tree-kill')(mtServer.pid, 'SIGKILL');
119+
}
120+
else {
121+
mtServer.kill();
122+
}
123+
};
124+
101125
var start = function (args, cb) {
102126
var async = require('async');
103127
console.log(chalk.magenta('reconfiguring database, starting app server'));
104-
var pwd = shell.pwd();
105128
var dirForMiddle = path.join(
106129
ctx.paths.projectRoot, 'appserver/java-spring'
107130
);
@@ -115,43 +138,53 @@ var start = function (args, cb) {
115138
'';
116139
var loadCmd = gradleCmd + ' dbLoad' + dbLoadParam + ' --stacktrace';
117140

141+
var hasStarted = false;
142+
118143
async.series([
119-
shellCmd.bind(null, dirForMiddle, gradleCmd + ' dbInit', null),
120-
shellCmd.bind(null, dirForMiddle, gradleCmd + ' dbTeardown', null),
121-
shellCmd.bind(null, dirForMiddle, gradleCmd + ' dbInit', null),
122-
shellCmd.bind(null, dirForMiddle, gradleCmd + ' dbConfigure', null),
123-
shellCmd.bind(null, dirForMiddle, gradleCmd + ' test', null),
124144
shellCmd.bind(
125-
null, dirForMiddle, loadCmd, null
145+
null, dirForMiddle, gradleCmd + ' dbInit --no-daemon', null
146+
),
147+
shellCmd.bind(
148+
null, dirForMiddle, gradleCmd + ' dbTeardown --no-daemon', null
149+
),
150+
shellCmd.bind(
151+
null, dirForMiddle, gradleCmd + ' dbInit --no-daemon', null
152+
),
153+
shellCmd.bind(
154+
null, dirForMiddle, gradleCmd + ' dbConfigure --no-daemon', null
155+
),
156+
shellCmd.bind(
157+
null, dirForMiddle, gradleCmd + ' test --no-daemon', null
158+
),
159+
shellCmd.bind(
160+
null, dirForMiddle, loadCmd + ' --no-daemon', null
126161
),
127162
shellCmd.bind(
128163
null,
129164
dirForMiddle,
130-
gradleCmd + ' bootrun',
165+
gradleCmd + ' bootrun --no-daemon',
131166
'marklogic.samplestack.Application - Started Application'
132167
),
133168
], function (err, results) {
134-
console.log(' ');
135-
$.util.log(chalk.green('detected middle tier started'));
136-
var mtServer = results[results.length - 1];
137-
ctx.setActiveServer('middle-tier', {
138-
close: function (cb) {
139-
console.log('shutting down Java middle tier');
140-
mtServer.on('exit', function () {
141-
cb();
142-
});
143-
mtServer.kill();
144-
}
145-
});
146-
147-
pokeServer(function () {
148-
console.log(chalk.magenta('preparations complete'));
149-
cb(err);
150-
151-
});
169+
if (!hasStarted) {
170+
hasStarted = true;
171+
console.log(' ');
172+
$.util.log(chalk.green('detected middle tier started'));
173+
mtServer = results[results.length - 1];
174+
ctx.setActiveServer('middle-tier', {
175+
close: closeServer
176+
});
177+
178+
pokeServer(function () {
179+
console.log(chalk.magenta('preparations complete'));
180+
cb(err);
181+
182+
});
183+
}
152184
});
153185
};
154186

155187
module.exports = {
156-
start: start
188+
start: start,
189+
close: closeServer
157190
};

shared/js/dev-tasks/e2e/protractor.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ var go = function (args, cb) {
137137

138138
var ptorProc = cp.spawn('node', [ptorPath, confPath], { stdio: 'inherit' });
139139
ptorProc.on('exit', function (code) {
140-
process.exit(code);
140+
cb(code);
141141
});
142142

143-
var cucumberParser = require('./cucumberParser');
144-
cucumberParser.handle(args, ptorConfig, ptorProc, cb);
143+
// var cucumberParser = require('./cucumberParser');
144+
// cucumberParser.handle(args, ptorConfig, ptorProc, cb);
145145
};
146146

147147
module.exports = {

shared/js/dev-tasks/e2e/seleniumLocal.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
/*
2-
* Copyright 2012-2015 MarkLogic Corporation
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
1+
/*
2+
* Copyright 2012-2015 MarkLogic Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
1616

1717
var childProcess = require('child_process');
1818
var path = require('path');
@@ -112,9 +112,7 @@ var start = function (args, cb) {
112112
ctx.setActiveServer('selenium', {
113113
url: url,
114114
close: function (cb) {
115-
server.on('exit', function () {
116-
cb();
117-
});
115+
cb();
118116
server.kill();
119117
}
120118
});

0 commit comments

Comments
 (0)