Improve the restart process on instances

This commit is contained in:
Aurélien Georget 2015-11-10 16:29:34 +01:00
parent 09785da3a7
commit 1707cdf3e4
8 changed files with 225 additions and 168 deletions

View File

@ -128,9 +128,9 @@ module.exports = function (strapi) {
strapi.controllers = {}; strapi.controllers = {};
strapi.models = {}; strapi.models = {};
strapi.policies = {}; strapi.policies = {};
});
cb(); cb();
});
}, },
/** /**

View File

@ -4,6 +4,9 @@
* Module dependencies * Module dependencies
*/ */
// Node.js core.
const cluster = require('cluster');
// Public node modules. // Public node modules.
const _ = require('lodash'); const _ = require('lodash');
@ -36,6 +39,7 @@ module.exports = function (strapi) {
*/ */
initialize: function (cb) { initialize: function (cb) {
if ((cluster.isWorker && strapi.config.reload.workers > 0) || (cluster.isMaster && strapi.config.reload.workers < 1)) {
let route; let route;
let controller; let controller;
let action; let action;
@ -139,6 +143,7 @@ module.exports = function (strapi) {
this.app.emit('error', err, this); this.app.emit('error', err, this);
} }
}); });
}
cb(); cb();
}, },
@ -148,6 +153,8 @@ module.exports = function (strapi) {
*/ */
reload: function () { reload: function () {
delete strapi.router;
hook.initialize(function (err) { hook.initialize(function (err) {
if (err) { if (err) {
strapi.log.error('Failed to reinitialize the router.'); strapi.log.error('Failed to reinitialize the router.');

View File

@ -83,8 +83,11 @@ module.exports = function (strapi) {
socket.on('connect', function () { socket.on('connect', function () {
firstConnectionAttempt = false; firstConnectionAttempt = false;
strapi.once('bootstrap:done', function () {
_self.connectWithStudio(socket); _self.connectWithStudio(socket);
}); });
});
socket.on('error', function (err) { socket.on('error', function (err) {
strapi.log.warn(err); strapi.log.warn(err);
@ -334,9 +337,11 @@ module.exports = function (strapi) {
*/ */
rebuild: function (data, cb) { rebuild: function (data, cb) {
strapi.restart(); process.nextTick(function () {
strapi.restart(function () {
cb(null, true); cb(null, true);
});
});
}, },
/** /**

View File

@ -5,6 +5,7 @@
*/ */
// Node.js core. // Node.js core.
const cluster = require('cluster');
const path = require('path'); const path = require('path');
const spawn = require('child_process').spawnSync; const spawn = require('child_process').spawnSync;
@ -59,8 +60,9 @@ module.exports = function (strapi) {
*/ */
initialize: function (cb) { initialize: function (cb) {
if (_.isPlainObject(strapi.config.orm) && !_.isEmpty(strapi.config.orm)) { if (_.isPlainObject(strapi.config.orm) && !_.isEmpty(strapi.config.orm) && ((cluster.isWorker && strapi.config.reload.workers > 0) || (cluster.isMaster && strapi.config.reload.workers < 1))) {
strapi.adapters = {}; strapi.adapters = {};
strapi.collections = [];
// Expose a new instance of Waterline. // Expose a new instance of Waterline.
if (!strapi.orm) { if (!strapi.orm) {
@ -148,7 +150,11 @@ module.exports = function (strapi) {
// Finally, load the collection in the Waterline instance. // Finally, load the collection in the Waterline instance.
try { try {
strapi.orm.loadCollection(Waterline.Collection.extend(definition)); const collection = strapi.orm.loadCollection(Waterline.Collection.extend(definition));
if (_.isFunction(collection)) {
strapi.collections.push(collection);
}
} catch (err) { } catch (err) {
strapi.log.error('Impossible to register the `' + model + '` model.'); strapi.log.error('Impossible to register the `' + model + '` model.');
process.exit(1); process.exit(1);
@ -159,8 +165,8 @@ module.exports = function (strapi) {
// globally expose models. // globally expose models.
strapi.orm.initialize({ strapi.orm.initialize({
adapters: strapi.adapters, adapters: strapi.adapters,
models: strapi.models,
connections: strapi.config.orm.connections, connections: strapi.config.orm.connections,
collections: strapi.collections,
defaults: { defaults: {
connection: strapi.config.orm.defaultConnection connection: strapi.config.orm.defaultConnection
} }
@ -171,7 +177,6 @@ module.exports = function (strapi) {
global[globalName] = strapi.orm.collections[model]; global[globalName] = strapi.orm.collections[model];
}); });
} }
});
// Parse each models and look for associations. // Parse each models and look for associations.
_.forEach(strapi.orm.collections, function (definition, model) { _.forEach(strapi.orm.collections, function (definition, model) {
@ -194,11 +199,12 @@ module.exports = function (strapi) {
usefulFunctions: true usefulFunctions: true
}); });
} }
} else {
strapi.log.warn('Waterline ORM disabled!');
}
cb(); cb();
});
} else {
cb();
}
}, },
/** /**
@ -207,6 +213,8 @@ module.exports = function (strapi) {
reload: function () { reload: function () {
hook.teardown(function () { hook.teardown(function () {
delete strapi.orm;
hook.initialize(function (err) { hook.initialize(function (err) {
if (err) { if (err) {
strapi.log.error('Failed to reinitialize the ORM hook.'); strapi.log.error('Failed to reinitialize the ORM hook.');

View File

@ -59,14 +59,28 @@ module.exports = function initialize(cb) {
} }
}); });
// Only run the application bootstrap if
// we are in a master cluster.
if (cluster.isMaster) { if (cluster.isMaster) {
_.forEach(cluster.workers, function (worker) {
worker.on('message', function () {
self.emit('bootstrap:done');
});
});
}
// Only run the application bootstrap on master cluster if we don't have any workers.
// Else, run the bootstrap logic on the workers.
if ((cluster.isWorker && strapi.config.reload.workers > 0) || (cluster.isMaster && strapi.config.reload.workers < 1)) {
self.runBootstrap(function afterBootstrap(err) { self.runBootstrap(function afterBootstrap(err) {
if (err) { if (err) {
self.log.error('Bootstrap encountered an error.'); self.log.error('Bootstrap encountered an error.');
return cb(self.log.error(err)); return cb(self.log.error(err));
} }
if (cluster.isWorker) {
process.send('message');
} else {
self.emit('bootstrap:done');
}
}); });
} }

View File

@ -123,7 +123,7 @@ module.exports = function (strapi) {
// Prepare all other hooks. // Prepare all other hooks.
prepare: function prepareHooks(cb) { prepare: function prepareHooks(cb) {
async.each(_.without(_.keys(hooks), '_config', '_api'), function (id, cb) { async.each(_.without(_.keys(hooks), '_config', '_api', 'studio'), function (id, cb) {
prepareHook(id); prepareHook(id);
process.nextTick(cb); process.nextTick(cb);
}, cb); }, cb);
@ -131,7 +131,7 @@ module.exports = function (strapi) {
// Apply the default config for all other hooks. // Apply the default config for all other hooks.
defaults: function defaultConfigHooks(cb) { defaults: function defaultConfigHooks(cb) {
async.each(_.without(_.keys(hooks), '_config', '_api'), function (id, cb) { async.each(_.without(_.keys(hooks), '_config', '_api', 'studio'), function (id, cb) {
const hook = hooks[id]; const hook = hooks[id];
applyDefaults(hook); applyDefaults(hook);
process.nextTick(cb); process.nextTick(cb);
@ -140,9 +140,19 @@ module.exports = function (strapi) {
// Load all other hooks. // Load all other hooks.
load: function loadOtherHooks(cb) { load: function loadOtherHooks(cb) {
async.each(_.without(_.keys(hooks), '_config', '_api'), function (id, cb) { async.each(_.without(_.keys(hooks), '_config', '_api', 'studio'), function (id, cb) {
loadHook(id, cb); loadHook(id, cb);
}, cb); }, cb);
},
// Load the studio hook.
studio: function loadStudioHook(cb) {
if (!hooks.studio) {
return cb();
}
prepareHook('studio');
applyDefaults(hooks.studio);
loadHook('studio', cb);
} }
}, },

View File

@ -16,11 +16,10 @@ const async = require('async');
* (useful for the Studio) * (useful for the Studio)
*/ */
module.exports = function () { module.exports = function (cb) {
const self = this; const self = this;
console.log(); console.log();
self.log.debug('Rebuilding application dictionary...');
// Update the Strapi status (might be used // Update the Strapi status (might be used
// by the core or some hooks). // by the core or some hooks).
@ -32,15 +31,15 @@ module.exports = function () {
// Rebuild the dictionaries. // Rebuild the dictionaries.
dictionaries: function (cb) { dictionaries: function (cb) {
self.hooks._config.reload(); self.on('hook:_config:reloaded', function () {
self.hooks._api.reload(); self.on('hook:_api:reloaded', function () {
cb(); cb();
}, });
// Make sure to delete the router stack. self.hooks._api.reload();
router: function (cb) { });
delete self.router;
cb(); self.hooks._config.reload();
} }
}, },
@ -54,31 +53,44 @@ module.exports = function () {
self.stop(); self.stop();
} }
// Kill every worker processes.
_.forEach(cluster.worker, function () {
process.kill(process.pid, 'SIGHUP');
});
// Tell the application the framework is reloading // Tell the application the framework is reloading
// (might be used by some hooks). // (might be used by some hooks).
self.reloading = true; self.reloading = true;
// Teardown Waterline adapters and // Teardown Waterline adapters and
// reload the Waterline ORM. // reload the Waterline ORM.
self.log.debug('Reloading the ORM...'); self.after('hook:waterline:reloaded', function () {
self.hooks.waterline.reload(); self.after('hook:router:reloaded', function () {
process.nextTick(function () {
// Reloading the router. cb();
self.log.debug('Reloading the router...'); });
self.hooks.router.reload();
// Update `strapi` status. // Update `strapi` status.
self.reloaded = true; self.reloaded = true;
self.reloading = false; self.reloading = false;
// Finally inform the developer everything seems ok. // Finally inform the developer everything seems ok.
self.log.info('Dictionary successfully rebuilt'); if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers < 1) {
self.log.info('Application\'s dictionnary updated');
self.log.warn('You still need to restart your server to fully enjoy changes...'); self.log.warn('You still need to restart your server to fully enjoy changes...');
}
// Kill every worker processes.
_.forEach(cluster.workers, function () {
process.kill(process.pid, 'SIGHUP');
});
if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers > 0) {
self.log.info('Application restarted');
console.log(); console.log();
}
});
// Reloading the router.
self.hooks.router.reload();
});
// Reloading the ORM.
self.hooks.waterline.reload();
}); });
}; };

View File

@ -129,6 +129,7 @@
"no-else-return": 0, "no-else-return": 0,
"no-extra-parens": 0, "no-extra-parens": 0,
"no-implicit-coercion": 0, "no-implicit-coercion": 0,
"no-inner-declarations": 0,
"no-invalid-this": 0, "no-invalid-this": 0,
"no-negated-condition": 0, "no-negated-condition": 0,
"no-throw-literal": 0, "no-throw-literal": 0,