mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Cleaned up boot require order, debugs & inlined mount
- Continuing cleanup and clarification of the boot process - By locating requires and inits more closely together its easier to see what happens where and to get timings - Improved consistency of the debug begin/end statements - Added "Step" comments to the main process - Inlined the mountGhost function, for readability and consistency with the other steps
This commit is contained in:
parent
05b77397b6
commit
089655c2e2
1 changed files with 79 additions and 70 deletions
149
core/boot.js
149
core/boot.js
|
@ -10,7 +10,9 @@ require('./server/overrides');
|
||||||
const debug = require('ghost-ignition').debug('boot');
|
const debug = require('ghost-ignition').debug('boot');
|
||||||
// END OF GLOBAL REQUIRES
|
// END OF GLOBAL REQUIRES
|
||||||
|
|
||||||
class BootLogger {
|
/**
|
||||||
|
* Helper class to create consistent log messages
|
||||||
|
*/class BootLogger {
|
||||||
constructor(logging, startTime) {
|
constructor(logging, startTime) {
|
||||||
this.logging = logging;
|
this.logging = logging;
|
||||||
this.startTime = startTime;
|
this.startTime = startTime;
|
||||||
|
@ -21,6 +23,21 @@ class BootLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to handle sending server ready notifications
|
||||||
|
*/
|
||||||
|
function notifyServerReady(error) {
|
||||||
|
const notify = require('./server/notify');
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
debug('Notifying server ready (error)');
|
||||||
|
notify.notifyServerReady(error);
|
||||||
|
} else {
|
||||||
|
debug('Notifying server ready (success)');
|
||||||
|
notify.notifyServerReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Database into a ready state
|
* Get the Database into a ready state
|
||||||
* - DatabaseStateManager handles doing all this for us
|
* - DatabaseStateManager handles doing all this for us
|
||||||
|
@ -33,31 +50,31 @@ async function initDatabase({config, logging}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core is intended to be all the bits of Ghost that are shared and we can't do anything without
|
* Core is intended to be all the bits of Ghost that are fundamental and we can't do anything without them!
|
||||||
* (There's more to do to make this true)
|
* (There's more to do to make this true)
|
||||||
*/
|
*/
|
||||||
async function initCore({ghostServer}) {
|
async function initCore({ghostServer}) {
|
||||||
debug('Begin: initCore');
|
debug('Begin: initCore');
|
||||||
const settings = require('./server/services/settings');
|
|
||||||
const jobService = require('./server/services/jobs');
|
// Initialize Ghost core internationalization - this is basically used to colocate all of our error message strings
|
||||||
const models = require('./server/models');
|
debug('Begin: i18n');
|
||||||
const {i18n} = require('./server/lib/common');
|
const {i18n} = require('./server/lib/common');
|
||||||
|
|
||||||
ghostServer.registerCleanupTask(async () => {
|
|
||||||
await jobService.shutdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize Ghost core internationalization
|
|
||||||
i18n.init();
|
i18n.init();
|
||||||
debug('Default i18n done for core');
|
debug('End: i18n');
|
||||||
|
|
||||||
|
// Models are the heart of Ghost - this is a syncronous operation
|
||||||
|
debug('Begin: models');
|
||||||
|
const models = require('./server/models');
|
||||||
models.init();
|
models.init();
|
||||||
debug('Models done');
|
debug('End: models');
|
||||||
|
|
||||||
|
// Settings are a core concept we use settings to store key-value pairs used in critical pathways as well as public data like the site title
|
||||||
|
debug('Begin: settings');
|
||||||
|
const settings = require('./server/services/settings');
|
||||||
await settings.init();
|
await settings.init();
|
||||||
|
debug('End: settings');
|
||||||
|
|
||||||
// The URLService is a core part of Ghost, which depends on models
|
// The URLService is a core part of Ghost, which depends on models. It needs moving from the frontend to make this clear.
|
||||||
// It needs moving from the frontend to make this clear
|
|
||||||
debug('Begin: Url Service');
|
debug('Begin: Url Service');
|
||||||
const urlService = require('./frontend/services/url');
|
const urlService = require('./frontend/services/url');
|
||||||
// Note: there is no await here, we do not wait for the url service to finish
|
// Note: there is no await here, we do not wait for the url service to finish
|
||||||
|
@ -66,24 +83,33 @@ async function initCore({ghostServer}) {
|
||||||
urlService.init();
|
urlService.init();
|
||||||
debug('End: Url Service');
|
debug('End: Url Service');
|
||||||
|
|
||||||
|
// Job Service allows parts of Ghost to run in the background
|
||||||
|
debug('Begin: Job Service');
|
||||||
|
const jobService = require('./server/services/jobs');
|
||||||
|
ghostServer.registerCleanupTask(async () => {
|
||||||
|
await jobService.shutdown();
|
||||||
|
});
|
||||||
|
debug('End: Job Service');
|
||||||
|
|
||||||
debug('End: initCore');
|
debug('End: initCore');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frontend is intended to be just Ghost's frontend
|
* Frontend is intended to be just Ghost's frontend
|
||||||
* This is technically wrong atm because the theme service & frontend settings services contain
|
* This is technically wrong currently because the theme & frontend settings services contain code used by the API to upload themes & settings
|
||||||
* code used by the API to upload themes and settings
|
|
||||||
*/
|
*/
|
||||||
async function initFrontend() {
|
async function initFrontend() {
|
||||||
debug('Begin: initFrontend');
|
debug('Begin: initFrontend');
|
||||||
const themeService = require('./frontend/services/themes');
|
|
||||||
|
debug('Begin: Frontend Settings');
|
||||||
const frontendSettings = require('./frontend/services/settings');
|
const frontendSettings = require('./frontend/services/settings');
|
||||||
|
|
||||||
await frontendSettings.init();
|
await frontendSettings.init();
|
||||||
debug('Frontend settings done');
|
debug('End: Frontend Settings');
|
||||||
|
|
||||||
|
debug('Begin: Themes');
|
||||||
|
const themeService = require('./frontend/services/themes');
|
||||||
await themeService.init();
|
await themeService.init();
|
||||||
debug('Themes done');
|
debug('End: Themes');
|
||||||
|
|
||||||
debug('End: initFrontend');
|
debug('End: initFrontend');
|
||||||
}
|
}
|
||||||
|
@ -107,27 +133,32 @@ async function initExpressApps() {
|
||||||
*/
|
*/
|
||||||
async function initServices({config}) {
|
async function initServices({config}) {
|
||||||
debug('Begin: initServices');
|
debug('Begin: initServices');
|
||||||
const themeService = require('./frontend/services/themes');
|
|
||||||
const frontendSettings = require('./frontend/services/settings');
|
|
||||||
const appService = require('./frontend/services/apps');
|
|
||||||
const urlUtils = require('./shared/url-utils');
|
|
||||||
|
|
||||||
// CASE: When Ghost is ready with bootstrapping (db migrations etc.), we can trigger the router creation.
|
debug('Begin: Dynamic Routing');
|
||||||
// Reason is that the routers access the routes.yaml, which shouldn't and doesn't have to be validated to
|
// Dynamic routing is generated from the routes.yaml file, which is part of the settings service
|
||||||
// start Ghost in maintenance mode.
|
// When Ghost's DB and core are loaded, we can access this file and call routing.bootstrap.start
|
||||||
// Routing is currently a bridge between the frontend and API
|
// However this _must_ happen after the express Apps are loaded, hence why this is here and not in initFrontend
|
||||||
|
// Routing is currently tightly coupled between the frontend and backend
|
||||||
const routing = require('./frontend/services/routing');
|
const routing = require('./frontend/services/routing');
|
||||||
// We pass the themeService API version here, so that the frontend services are less tightly-coupled
|
const themeService = require('./frontend/services/themes');
|
||||||
|
// We pass the themeService API version here, so that the frontend services are slightly less tightly-coupled
|
||||||
routing.bootstrap.start(themeService.getApiVersion());
|
routing.bootstrap.start(themeService.getApiVersion());
|
||||||
|
|
||||||
const settings = require('./server/services/settings');
|
const settings = require('./server/services/settings');
|
||||||
|
const frontendSettings = require('./frontend/services/settings');
|
||||||
|
const getRoutesHash = () => frontendSettings.getCurrentHash('routes');
|
||||||
|
await settings.syncRoutesHash(getRoutesHash);
|
||||||
|
debug('End: Dynamic Routing');
|
||||||
|
|
||||||
|
debug('Begin: Services');
|
||||||
const permissions = require('./server/services/permissions');
|
const permissions = require('./server/services/permissions');
|
||||||
const xmlrpc = require('./server/services/xmlrpc');
|
const xmlrpc = require('./server/services/xmlrpc');
|
||||||
const slack = require('./server/services/slack');
|
const slack = require('./server/services/slack');
|
||||||
const {mega} = require('./server/services/mega');
|
const {mega} = require('./server/services/mega');
|
||||||
const webhooks = require('./server/services/webhooks');
|
const webhooks = require('./server/services/webhooks');
|
||||||
|
const appService = require('./frontend/services/apps');
|
||||||
const scheduling = require('./server/adapters/scheduling');
|
const scheduling = require('./server/adapters/scheduling');
|
||||||
const getRoutesHash = () => frontendSettings.getCurrentHash('routes');
|
|
||||||
|
const urlUtils = require('./shared/url-utils');
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
permissions.init(),
|
permissions.init(),
|
||||||
|
@ -135,7 +166,6 @@ async function initServices({config}) {
|
||||||
slack.listen(),
|
slack.listen(),
|
||||||
mega.listen(),
|
mega.listen(),
|
||||||
webhooks.listen(),
|
webhooks.listen(),
|
||||||
settings.syncRoutesHash(getRoutesHash),
|
|
||||||
appService.init(),
|
appService.init(),
|
||||||
scheduling.init({
|
scheduling.init({
|
||||||
// NOTE: When changing API version need to consider how to migrate custom scheduling adapters
|
// NOTE: When changing API version need to consider how to migrate custom scheduling adapters
|
||||||
|
@ -143,8 +173,7 @@ async function initServices({config}) {
|
||||||
apiUrl: urlUtils.urlFor('api', {version: 'v3', versionType: 'admin'}, true)
|
apiUrl: urlUtils.urlFor('api', {version: 'v3', versionType: 'admin'}, true)
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
debug('End: Services');
|
||||||
debug('XMLRPC, Slack, MEGA, Webhooks, Scheduling, Permissions done');
|
|
||||||
|
|
||||||
// Initialise analytics events
|
// Initialise analytics events
|
||||||
if (config.get('segment:key')) {
|
if (config.get('segment:key')) {
|
||||||
|
@ -180,30 +209,6 @@ async function initBackgroundServices({config}) {
|
||||||
debug('End: initBackgroundServices');
|
debug('End: initBackgroundServices');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Mount the now loaded main Ghost App onto our pre-loaded root app
|
|
||||||
* - Now that we have the Ghost App ready to receive requests, disable global maintenance mode
|
|
||||||
*/
|
|
||||||
function mountGhost(rootApp, ghostApp) {
|
|
||||||
debug('Begin: mountGhost');
|
|
||||||
const urlService = require('./frontend/services/url');
|
|
||||||
rootApp.disable('maintenance');
|
|
||||||
rootApp.use(urlService.utils.getSubdir(), ghostApp);
|
|
||||||
debug('End: mountGhost');
|
|
||||||
}
|
|
||||||
|
|
||||||
function notifyServerReady(error) {
|
|
||||||
const notify = require('./server/notify');
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
debug('Notifying server ready (error)');
|
|
||||||
notify.notifyServerReady(error);
|
|
||||||
} else {
|
|
||||||
debug('Notifying server ready (success)');
|
|
||||||
notify.notifyServerReady();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ----------------------------------
|
* ----------------------------------
|
||||||
* Boot Ghost - The magic starts here
|
* Boot Ghost - The magic starts here
|
||||||
|
@ -222,6 +227,7 @@ async function bootGhost() {
|
||||||
let logging;
|
let logging;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Step 0 - Do initial requires of fundamental shared components
|
||||||
// Config must be the first thing we do, because it is required for absolutely everything
|
// Config must be the first thing we do, because it is required for absolutely everything
|
||||||
debug('Begin: Load config');
|
debug('Begin: Load config');
|
||||||
const config = require('./shared/config');
|
const config = require('./shared/config');
|
||||||
|
@ -244,7 +250,7 @@ async function bootGhost() {
|
||||||
require('./shared/sentry');
|
require('./shared/sentry');
|
||||||
debug('End: Load sentry');
|
debug('End: Load sentry');
|
||||||
|
|
||||||
// Start server with minimal app in global maintenance mode
|
// Step 1 - Start server with minimal app in global maintenance mode
|
||||||
debug('Begin: load server + minimal app');
|
debug('Begin: load server + minimal app');
|
||||||
const rootApp = require('./app');
|
const rootApp = require('./app');
|
||||||
const GhostServer = require('./server/ghost-server');
|
const GhostServer = require('./server/ghost-server');
|
||||||
|
@ -253,32 +259,35 @@ async function bootGhost() {
|
||||||
bootLogger.log('server started');
|
bootLogger.log('server started');
|
||||||
debug('End: load server + minimal app');
|
debug('End: load server + minimal app');
|
||||||
|
|
||||||
// Get the DB ready
|
// Step 2 - Get the DB ready
|
||||||
debug('Begin: Get DB ready');
|
debug('Begin: Get DB ready');
|
||||||
await initDatabase({config, logging});
|
await initDatabase({config, logging});
|
||||||
bootLogger.log('database ready');
|
bootLogger.log('database ready');
|
||||||
debug('End: Get DB ready');
|
debug('End: Get DB ready');
|
||||||
|
|
||||||
// Load Ghost with all its services
|
// Step 3 - Load Ghost with all its services
|
||||||
debug('Begin: Load Ghost Core Services');
|
debug('Begin: Load Ghost Services & Apps');
|
||||||
await initCore({ghostServer});
|
await initCore({ghostServer});
|
||||||
await initFrontend();
|
await initFrontend();
|
||||||
const ghostApp = await initExpressApps({});
|
const ghostApp = await initExpressApps({});
|
||||||
await initServices({config});
|
await initServices({config});
|
||||||
debug('End: Load Ghost Core Services');
|
debug('End: Load Ghost Services & Apps');
|
||||||
|
|
||||||
// Mount the full Ghost app onto the minimal root app & disable maintenance mode
|
// Step 4 - Mount the full Ghost app onto the minimal root app & disable maintenance mode
|
||||||
mountGhost(rootApp, ghostApp);
|
debug('Begin: mountGhost');
|
||||||
|
const urlUtils = require('./shared/url-utils');
|
||||||
|
rootApp.disable('maintenance');
|
||||||
|
rootApp.use(urlUtils.getSubdir(), ghostApp);
|
||||||
|
debug('End: mountGhost');
|
||||||
|
|
||||||
// We are technically done here
|
// Step 5 - We are technically done here - let everyone know!
|
||||||
bootLogger.log('booted');
|
bootLogger.log('booted');
|
||||||
|
|
||||||
notifyServerReady();
|
notifyServerReady();
|
||||||
|
|
||||||
// Init our background services, we don't wait for this to finish
|
// Step 6 - Init our background services, we don't wait for this to finish
|
||||||
initBackgroundServices({config});
|
initBackgroundServices({config});
|
||||||
|
|
||||||
// We return the server for testing purposes
|
// We return the server purely for testing purposes
|
||||||
debug('End Boot: Returning Ghost Server');
|
debug('End Boot: Returning Ghost Server');
|
||||||
return ghostServer;
|
return ghostServer;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
Loading…
Reference in a new issue