Skip to content

Commit 771eb83

Browse files
committed
Improved boot process
1 parent 341825d commit 771eb83

File tree

6 files changed

+115
-47
lines changed

6 files changed

+115
-47
lines changed

bin/cli.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,19 @@ var commandRawArgs = process.argv.slice(3);
1515
var arg1 = argv._[1];
1616
var force = argv.force ? true : false;
1717

18+
var fileExistsSync = function (filePath) {
19+
try {
20+
fs.accessSync(filePath, fs.constants.F_OK);
21+
} catch (err) {
22+
return false;
23+
}
24+
return true;
25+
};
26+
1827
var parsePackageFile = function (moduleDir) {
1928
var packageFile = moduleDir + '/package.json';
2029
try {
21-
if (fs.existsSync(packageFile)) {
30+
if (fileExistsSync(packageFile)) {
2231
return JSON.parse(fs.readFileSync(packageFile, {encoding: 'utf8'}));
2332
}
2433
} catch (e) {}
@@ -173,7 +182,7 @@ var confirmReplaceSetup = function (confirm) {
173182

174183
if (command == 'create') {
175184
if (arg1) {
176-
if (fs.existsSync(destDir)) {
185+
if (fileExistsSync(destDir)) {
177186
if (force) {
178187
confirmReplaceSetup(true);
179188
} else {

index.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ SocketCluster.prototype._init = function (options) {
182182
var pathHasher = crypto.createHash('md5');
183183
pathHasher.update(self._paths.appDirPath, 'utf8');
184184
var pathHash = pathHasher.digest('hex').substr(0, 10);
185-
// Trimp it because some OSes (e.g. OSX) do not like long path names for domain sockets.
185+
// Trim it because some OSes (e.g. OSX) do not like long path names for domain sockets.
186186
var shortAppName = self.options.appName.substr(0, 13);
187187

188188
if (process.platform == 'win32') {
@@ -199,7 +199,7 @@ SocketCluster.prototype._init = function (options) {
199199
socketParentDir = os.tmpdir() + '/socketcluster/';
200200
socketDir = socketParentDir + shortAppName + '_' + pathHash + '/';
201201
}
202-
if (fs.existsSync(socketDir)) {
202+
if (self._fileExistsSync(socketDir)) {
203203
try {
204204
fs.removeSync(socketDir);
205205
} catch (err) {
@@ -329,6 +329,15 @@ SocketCluster.prototype._init = function (options) {
329329
}
330330
};
331331

332+
SocketCluster.prototype._fileExistsSync = function (filePath) {
333+
try {
334+
fs.accessSync(filePath, fs.constants.F_OK);
335+
} catch (err) {
336+
return false;
337+
}
338+
return true;
339+
};
340+
332341
SocketCluster.prototype._getBrokerSocketName = function (brokerId) {
333342
return 'b' + brokerId;
334343
};

sample/master.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var scHotReboot = require('sc-hot-reboot');
2+
3+
module.exports.run = function (socketCluster) {
4+
socketCluster.on(socketCluster.EVENT_WORKER_CLUSTER_START, function (workerClusterInfo) {
5+
console.log(' >> WorkerCluster PID:', workerClusterInfo.pid);
6+
});
7+
8+
if (socketCluster.options.environment == 'dev') {
9+
// This will cause SC workers to reboot when code changes anywhere in the app directory.
10+
// The second options argument here is passed directly to chokidar.
11+
// See https://github.com/paulmillr/chokidar#api for details.
12+
console.log(` !! The sc-hot-reboot plugin is watching for code changes in the ${__dirname} directory`);
13+
scHotReboot.attach(socketCluster, {
14+
cwd: __dirname,
15+
ignored: ['public', 'node_modules', 'README.md', 'Dockerfile', 'server.js', 'master.js', 'broker.js', /[\/\\]\./, '*.log']
16+
});
17+
}
18+
};

sample/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
"express": "4.14.0",
1414
"minimist": "1.1.0",
1515
"morgan": "1.7.0",
16-
"scc-broker-client": "~1.3.0",
16+
"sc-errors": "~1.3.2",
1717
"sc-framework-health-check": "~1.0.0",
1818
"sc-hot-reboot": "~1.0.0",
19+
"scc-broker-client": "~1.3.0",
1920
"serve-static": "1.11.2",
2021
"socketcluster": "~6.3.1",
2122
"socketcluster-client": "~6.2.2"

sample/server.js

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
var fs = require('fs');
22
var argv = require('minimist')(process.argv.slice(2));
3+
var scErrors = require('sc-errors');
4+
var TimeoutError = scErrors.TimeoutError;
5+
36
var SocketCluster = require('socketcluster').SocketCluster;
4-
var scHotReboot = require('sc-hot-reboot');
57

68
var workerControllerPath = argv.wc || process.env.SOCKETCLUSTER_WORKER_CONTROLLER;
79
var brokerControllerPath = argv.bc || process.env.SOCKETCLUSTER_BROKER_CONTROLLER;
@@ -33,6 +35,7 @@ var options = {
3335
environment: environment
3436
};
3537

38+
var SOCKETCLUSTER_CONTROLLER_BOOT_TIMEOUT = Number(process.env.SOCKETCLUSTER_CONTROLLER_BOOT_TIMEOUT) || 10000;
3639
var SOCKETCLUSTER_OPTIONS;
3740

3841
if (process.env.SOCKETCLUSTER_OPTIONS) {
@@ -48,22 +51,29 @@ for (var i in SOCKETCLUSTER_OPTIONS) {
4851
var optionsControllerPath = argv.oc || process.env.SOCKETCLUSTER_OPTIONS_CONTROLLER;
4952
var masterControllerPath = argv.mc || process.env.SOCKETCLUSTER_MASTER_CONTROLLER;
5053

54+
var fileExists = function (filePath, callback) {
55+
fs.access(filePath, fs.constants.F_OK, (err) => {
56+
callback(!err);
57+
});
58+
};
59+
60+
var runMasterController = function (socketCluster, filePath) {
61+
var masterController = require(filePath);
62+
masterController.run(socketCluster);
63+
};
64+
5165
var launch = function (startOptions) {
5266
var socketCluster = new SocketCluster(startOptions);
67+
var masterController;
5368

5469
if (masterControllerPath) {
55-
var masterController = require(masterControllerPath);
56-
masterController.run(socketCluster);
57-
}
58-
59-
if (environment == 'dev') {
60-
// This will cause SC workers to reboot when code changes anywhere in the app directory.
61-
// The second options argument here is passed directly to chokidar.
62-
// See https://github.com/paulmillr/chokidar#api for details.
63-
console.log(` !! The sc-hot-reboot plugin is watching for code changes in the ${__dirname} directory`);
64-
scHotReboot.attach(socketCluster, {
65-
cwd: __dirname,
66-
ignored: ['public', 'node_modules', 'README.md', 'Dockerfile', 'server.js', 'broker.js', /[\/\\]\./, '*.log']
70+
runMasterController(socketCluster, masterControllerPath);
71+
} else {
72+
var defaultMasterControllerPath = __dirname + '/master.js';
73+
fileExists(defaultMasterControllerPath, (exists) => {
74+
if (exists) {
75+
runMasterController(socketCluster, defaultMasterControllerPath);
76+
}
6777
});
6878
}
6979
};
@@ -78,37 +88,49 @@ var start = function () {
7888
};
7989

8090
var bootCheckInterval = Number(process.env.SOCKETCLUSTER_BOOT_CHECK_INTERVAL) || 200;
91+
var bootStartTime = Date.now();
8192

82-
if (workerControllerPath) {
83-
// Detect when Docker volumes are ready.
84-
var startWhenFileIsReady = (filePath) => {
85-
return new Promise((resolve) => {
86-
if (!filePath) {
87-
resolve();
88-
return;
89-
}
90-
var checkIsReady = () => {
91-
fs.exists(filePath, (exists) => {
92-
if (exists) {
93-
resolve();
93+
// Detect when Docker volumes are ready.
94+
var startWhenFileIsReady = (filePath) => {
95+
return new Promise((resolve, reject) => {
96+
if (!filePath) {
97+
resolve();
98+
return;
99+
}
100+
var checkIsReady = () => {
101+
var now = Date.now();
102+
103+
fileExists(filePath, (exists) => {
104+
if (exists) {
105+
resolve();
106+
} else {
107+
if (now - bootStartTime >= SOCKETCLUSTER_CONTROLLER_BOOT_TIMEOUT) {
108+
var errorMessage = `Could not locate a controller file at path ${filePath} ` +
109+
`before SOCKETCLUSTER_CONTROLLER_BOOT_TIMEOUT`;
110+
var volumeBootTimeoutError = new TimeoutError(errorMessage);
111+
reject(volumeBootTimeoutError);
94112
} else {
95113
setTimeout(checkIsReady, bootCheckInterval);
96114
}
97-
});
98-
};
99-
checkIsReady();
100-
});
101-
};
102-
var filesReadyPromises = [
103-
startWhenFileIsReady(optionsControllerPath),
104-
startWhenFileIsReady(masterControllerPath),
105-
startWhenFileIsReady(workerControllerPath),
106-
startWhenFileIsReady(brokerControllerPath),
107-
startWhenFileIsReady(initControllerPath)
108-
];
109-
Promise.all(filesReadyPromises).then(() => {
110-
start();
115+
}
116+
});
117+
};
118+
checkIsReady();
111119
});
112-
} else {
120+
};
121+
122+
var filesReadyPromises = [
123+
startWhenFileIsReady(optionsControllerPath),
124+
startWhenFileIsReady(masterControllerPath),
125+
startWhenFileIsReady(workerControllerPath),
126+
startWhenFileIsReady(brokerControllerPath),
127+
startWhenFileIsReady(initControllerPath)
128+
];
129+
Promise.all(filesReadyPromises)
130+
.then(() => {
113131
start();
114-
}
132+
})
133+
.catch((err) => {
134+
console.error(err.stack);
135+
process.exit(1);
136+
});

test/internal/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@ var getTestSocketPath = require('./testsocketpath').getTestSocketPath;
1010
var scServer = childProcess.fork(__dirname + '/server.js');
1111
var resultSocketPath = getTestSocketPath();
1212

13+
var fileExistsSync = function (filePath) {
14+
try {
15+
fs.accessSync(filePath, fs.constants.F_OK);
16+
} catch (err) {
17+
return false;
18+
}
19+
return true;
20+
};
21+
1322
if (process.platform != 'win32') {
14-
if (fs.existsSync(resultSocketPath)) {
23+
if (fileExistsSync(resultSocketPath)) {
1524
fs.unlinkSync(resultSocketPath);
1625
}
1726
}

0 commit comments

Comments
 (0)