mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
✨ Finalised new boot process
- This commit removes the old boot process and any files that are no longer needed as a result - Remove the duplicate event for triggering inactive themes to load - Tidied up a few other bits
This commit is contained in:
parent
9e93ed7ef0
commit
481e2425af
12 changed files with 16 additions and 403 deletions
|
@ -208,7 +208,6 @@ async function bootGhost() {
|
|||
debug('End: Load sentry');
|
||||
|
||||
debug('Begin: load server + minimal app');
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
// Get minimal application in maintenance mode
|
||||
const rootApp = require('./app');
|
||||
|
@ -241,7 +240,7 @@ async function bootGhost() {
|
|||
mountGhost(rootApp, ghostApp);
|
||||
|
||||
// Announce Server Readiness
|
||||
logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's');
|
||||
logging.info('Ghost booted', (Date.now() - startTime) / 1000 + 's');
|
||||
debug('boot announcing readiness');
|
||||
GhostServer.announceServerReadiness();
|
||||
|
||||
|
|
|
@ -23,11 +23,8 @@ module.exports = {
|
|||
|
||||
debug('init themes', activeThemeName);
|
||||
|
||||
// Register a listener for server-start to load all themes
|
||||
events.on('server.start', function readAllThemesOnServerStart() {
|
||||
themeLoader.loadAllThemes();
|
||||
});
|
||||
events.on('themes.ready', function readAllThemesOnServerStart() {
|
||||
// Register a listener for when the server says we can start to load all themes
|
||||
events.on('themes.ready', function readAllThemesOnReady() {
|
||||
themeLoader.loadAllThemes();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
// ## Server Loader
|
||||
// Passes options through the boot process to get a server instance back
|
||||
const server = require('./server');
|
||||
const errors = require('@tryghost/errors');
|
||||
const GhostServer = require('./server/ghost-server');
|
||||
|
||||
// Set the default environment to be `development`
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
function makeGhost(options) {
|
||||
options = options || {};
|
||||
|
||||
return server(options)
|
||||
.catch((err) => {
|
||||
if (!errors.utils.isIgnitionError(err)) {
|
||||
err = new errors.GhostError({message: err.message, err: err});
|
||||
}
|
||||
|
||||
return GhostServer.announceServerReadiness(err)
|
||||
.finally(() => {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = makeGhost;
|
|
@ -1,74 +0,0 @@
|
|||
const KnexMigrator = require('knex-migrator');
|
||||
const config = require('../../../shared/config');
|
||||
const errors = require('@tryghost/errors');
|
||||
|
||||
const knexMigrator = new KnexMigrator({
|
||||
knexMigratorFilePath: config.get('paths:appRoot')
|
||||
});
|
||||
|
||||
module.exports.getState = () => {
|
||||
let state;
|
||||
let err;
|
||||
|
||||
return knexMigrator.isDatabaseOK()
|
||||
.then(() => {
|
||||
state = 1;
|
||||
return state;
|
||||
})
|
||||
.catch((_err) => {
|
||||
err = _err;
|
||||
|
||||
// CASE: database was never created
|
||||
if (err.code === 'DB_NOT_INITIALISED') {
|
||||
state = 2;
|
||||
return state;
|
||||
}
|
||||
|
||||
// CASE: you have created the database on your own, you have an existing none compatible db?
|
||||
if (err.code === 'MIGRATION_TABLE_IS_MISSING') {
|
||||
state = 3;
|
||||
return state;
|
||||
}
|
||||
|
||||
// CASE: database needs migrations
|
||||
if (err.code === 'DB_NEEDS_MIGRATION') {
|
||||
state = 4;
|
||||
return state;
|
||||
}
|
||||
|
||||
// CASE: database connection errors, unknown cases
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.dbInit = () => {
|
||||
return knexMigrator.init();
|
||||
};
|
||||
|
||||
module.exports.migrate = () => {
|
||||
return knexMigrator.migrate();
|
||||
};
|
||||
|
||||
module.exports.isDbCompatible = (connection) => {
|
||||
return connection.raw('SELECT `key` FROM settings WHERE `key`="databaseVersion";')
|
||||
.then((response) => {
|
||||
if (!response || !response[0].length) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new errors.DatabaseVersionError({
|
||||
message: 'Your database version is not compatible with Ghost 2.0.',
|
||||
help: 'Want to keep your DB? Use Ghost < 1.0.0 or the "0.11" branch.' +
|
||||
'\n\n\n' +
|
||||
'Want to migrate Ghost 0.11 to 2.0? Please visit https://ghost.org/docs/update/'
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
// CASE settings table doesn't exists
|
||||
if (err.errno === 1146 || err.errno === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
};
|
|
@ -199,15 +199,6 @@ class GhostServer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} externalApp - express app instance
|
||||
* @return {Promise} Resolves once Ghost has switched HTTP Servers
|
||||
*/
|
||||
async swapHttpApp(externalApp) {
|
||||
await this._stopServer();
|
||||
await this.start(externalApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* ### Hammertime
|
||||
* To be called after `stop`
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
/**
|
||||
* make sure overrides get's called first!
|
||||
* - keeping the overrides import here works for installing Ghost as npm!
|
||||
*
|
||||
* the call order is the following:
|
||||
* - root index requires core module
|
||||
* - core index requires server
|
||||
* - overrides is the first package to load
|
||||
*/
|
||||
require('./overrides');
|
||||
|
||||
const debug = require('ghost-ignition').debug('boot:init');
|
||||
const Promise = require('bluebird');
|
||||
const config = require('../shared/config');
|
||||
const {events, i18n} = require('./lib/common');
|
||||
const logging = require('../shared/logging');
|
||||
const migrator = require('./data/db/migrator');
|
||||
const urlUtils = require('./../shared/url-utils');
|
||||
|
||||
// Frontend Components
|
||||
const themeService = require('../frontend/services/themes');
|
||||
const appService = require('../frontend/services/apps');
|
||||
const frontendSettings = require('../frontend/services/settings');
|
||||
|
||||
async function initialiseServices() {
|
||||
// CASE: When Ghost is ready with bootstrapping (db migrations etc.), we can trigger the router creation.
|
||||
// Reason is that the routers access the routes.yaml, which shouldn't and doesn't have to be validated to
|
||||
// start Ghost in maintenance mode.
|
||||
// Routing is a bridge between the frontend and API
|
||||
const routing = require('../frontend/services/routing');
|
||||
// We pass the themeService API version here, so that the frontend services are less tightly-coupled
|
||||
routing.bootstrap.start(themeService.getApiVersion());
|
||||
|
||||
const settings = require('./services/settings');
|
||||
const permissions = require('./services/permissions');
|
||||
const xmlrpc = require('./services/xmlrpc');
|
||||
const slack = require('./services/slack');
|
||||
const {mega} = require('./services/mega');
|
||||
const webhooks = require('./services/webhooks');
|
||||
const scheduling = require('./adapters/scheduling');
|
||||
|
||||
debug('`initialiseServices` Start...');
|
||||
const getRoutesHash = () => frontendSettings.getCurrentHash('routes');
|
||||
|
||||
await Promise.all([
|
||||
// Initialize the permissions actions and objects
|
||||
permissions.init(),
|
||||
xmlrpc.listen(),
|
||||
slack.listen(),
|
||||
mega.listen(),
|
||||
webhooks.listen(),
|
||||
settings.syncRoutesHash(getRoutesHash),
|
||||
appService.init(),
|
||||
scheduling.init({
|
||||
// NOTE: When changing API version need to consider how to migrate custom scheduling adapters
|
||||
// that rely on URL to lookup persisted scheduled records (jobs, etc.). Ref: https://github.com/TryGhost/Ghost/pull/10726#issuecomment-489557162
|
||||
apiUrl: urlUtils.urlFor('api', {version: 'v3', versionType: 'admin'}, true)
|
||||
})
|
||||
]);
|
||||
|
||||
debug('XMLRPC, Slack, MEGA, Webhooks, Scheduling, Permissions done');
|
||||
|
||||
// Initialise analytics events
|
||||
if (config.get('segment:key')) {
|
||||
require('./analytics-events').init();
|
||||
}
|
||||
|
||||
debug('...`initialiseServices` End');
|
||||
}
|
||||
|
||||
async function initializeRecurringJobs() {
|
||||
// we don't want to kick off scheduled/recurring jobs that will interfere with tests
|
||||
if (process.env.NODE_ENV.match(/^testing/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.get('backgroundJobs:emailAnalytics')) {
|
||||
const emailAnalyticsJobs = require('./services/email-analytics/jobs');
|
||||
await emailAnalyticsJobs.scheduleRecurringJobs();
|
||||
}
|
||||
}
|
||||
|
||||
const initExpressApps = async () => {
|
||||
await frontendSettings.init();
|
||||
debug('Frontend settings done');
|
||||
|
||||
await themeService.init();
|
||||
debug('Themes done');
|
||||
|
||||
const parentApp = require('./web/parent/app')();
|
||||
debug('Express Apps done');
|
||||
|
||||
return parentApp;
|
||||
};
|
||||
|
||||
/**
|
||||
* - initialise models
|
||||
* - initialise i18n
|
||||
* - start the ghost server
|
||||
* - load all settings into settings cache (almost every component makes use of this cache)
|
||||
* - enable maintenance mode if migrations are missing
|
||||
* - load active theme
|
||||
* - create our express apps (site, admin, api)
|
||||
*/
|
||||
const minimalRequiredSetupToStartGhost = async (dbState) => {
|
||||
const settings = require('./services/settings');
|
||||
const jobService = require('./services/jobs');
|
||||
const models = require('./models');
|
||||
const GhostServer = require('./ghost-server');
|
||||
|
||||
// Initialize Ghost core internationalization
|
||||
i18n.init();
|
||||
debug('Default i18n done for core');
|
||||
|
||||
models.init();
|
||||
debug('Models done');
|
||||
|
||||
const ghostServer = new GhostServer();
|
||||
|
||||
ghostServer.registerCleanupTask(async () => {
|
||||
await jobService.shutdown();
|
||||
});
|
||||
|
||||
// CASE: all good or db was just initialised
|
||||
if (dbState === 1 || dbState === 2) {
|
||||
await settings.init();
|
||||
debug('Settings done');
|
||||
const parentApp = await initExpressApps();
|
||||
ghostServer.rootApp = parentApp;
|
||||
|
||||
events.emit('db.ready');
|
||||
|
||||
await initialiseServices();
|
||||
}
|
||||
|
||||
// CASE: migrations required, put blog into maintenance mode
|
||||
if (dbState === 4) {
|
||||
config.set('maintenance:enabled', true);
|
||||
logging.info('Blog is in maintenance mode.');
|
||||
|
||||
ghostServer.rootApp = require('./web/maintenance');
|
||||
|
||||
try {
|
||||
migrator.migrate()
|
||||
.then(async () => {
|
||||
await settings.init();
|
||||
debug('Settings done');
|
||||
|
||||
const parentApp = await initExpressApps();
|
||||
ghostServer.swapHttpApp(parentApp);
|
||||
|
||||
events.emit('db.ready');
|
||||
|
||||
await initialiseServices();
|
||||
|
||||
config.set('maintenance:enabled', false);
|
||||
logging.info('Blog is out of maintenance mode.');
|
||||
|
||||
await GhostServer.announceServerReadiness();
|
||||
});
|
||||
} catch (err) {
|
||||
try {
|
||||
await GhostServer.announceServerReadiness(err);
|
||||
} finally {
|
||||
logging.error(err);
|
||||
setTimeout(() => {
|
||||
process.exit(1);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializeRecurringJobs();
|
||||
|
||||
return ghostServer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect to database.
|
||||
* Check db state.
|
||||
*/
|
||||
const isDatabaseInitialisationRequired = async () => {
|
||||
const db = require('./data/db/connection');
|
||||
|
||||
let dbState = await migrator.getState();
|
||||
|
||||
// CASE: db initialisation required, wait till finished
|
||||
if (dbState === 2) {
|
||||
await migrator.dbInit();
|
||||
}
|
||||
|
||||
// CASE: is db incompatible? e.g. you can't connect a 0.11 database with Ghost 1.0 or 2.0
|
||||
if (dbState === 3) {
|
||||
await migrator.isDbCompatible(db);
|
||||
|
||||
dbState = 2;
|
||||
await migrator.dbInit();
|
||||
}
|
||||
|
||||
return minimalRequiredSetupToStartGhost(dbState);
|
||||
};
|
||||
|
||||
module.exports = isDatabaseInitialisationRequired;
|
|
@ -1,6 +0,0 @@
|
|||
const MaintenanceApp = require('@tryghost/maintenance');
|
||||
const express = require('../../../shared/express');
|
||||
|
||||
module.exports = new MaintenanceApp({
|
||||
express
|
||||
}).app;
|
19
ghost.js
19
ghost.js
|
@ -1,14 +1,19 @@
|
|||
const argv = process.argv;
|
||||
/**
|
||||
* Internal CLI Placeholder
|
||||
*
|
||||
* If we want to add alternative commands, flags, or modify environment vars, it should all go here.
|
||||
* Important: This file should not contain any requires, unless we decide to add pretty-cli/commander type tools
|
||||
*
|
||||
**/
|
||||
|
||||
const mode = argv[2] || 'new';
|
||||
// Don't allow NODE_ENV to be null
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
const argv = process.argv;
|
||||
const mode = argv[2];
|
||||
|
||||
// Switch between boot modes
|
||||
switch (mode) {
|
||||
case 'old':
|
||||
case '3':
|
||||
// Old boot sequence
|
||||
require('./startup');
|
||||
break;
|
||||
default:
|
||||
// New boot sequence
|
||||
require('./core/boot')();
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
"@tryghost/kg-markdown-html-renderer": "4.0.0-rc.2",
|
||||
"@tryghost/kg-mobiledoc-html-renderer": "4.0.0-rc.1",
|
||||
"@tryghost/magic-link": "0.6.6",
|
||||
"@tryghost/maintenance": "0.1.0",
|
||||
"@tryghost/members-api": "1.0.0-rc.3",
|
||||
"@tryghost/members-csv": "0.4.4",
|
||||
"@tryghost/members-ssr": "0.8.10",
|
||||
|
|
44
startup.js
44
startup.js
|
@ -1,44 +0,0 @@
|
|||
// # Ghost Startup
|
||||
// Orchestrates the startup of Ghost when run from command line.
|
||||
|
||||
const startTime = Date.now();
|
||||
const debug = require('ghost-ignition').debug('boot:index');
|
||||
// Sentry must be initialised early on
|
||||
const sentry = require('./core/shared/sentry');
|
||||
|
||||
debug('First requires...');
|
||||
|
||||
const ghost = require('./core');
|
||||
|
||||
debug('Required ghost');
|
||||
|
||||
const express = require('./core/shared/express');
|
||||
const logging = require('./core/shared/logging');
|
||||
const urlService = require('./core/frontend/services/url');
|
||||
|
||||
logging.info('Boot Mode: 3.0');
|
||||
// This is what listen gets called on, it needs to be a full Express App
|
||||
const ghostApp = express('ghost');
|
||||
|
||||
// Use the request handler at the top level
|
||||
// @TODO: decide if this should be here or in parent App - should it come after request id mw?
|
||||
ghostApp.use(sentry.requestHandler);
|
||||
|
||||
debug('Initialising Ghost');
|
||||
|
||||
ghost().then(function (ghostServer) {
|
||||
// Mount our Ghost instance on our desired subdirectory path if it exists.
|
||||
ghostApp.use(urlService.utils.getSubdir(), ghostServer.rootApp);
|
||||
|
||||
debug('Starting Ghost');
|
||||
// Let Ghost handle starting our server instance.
|
||||
return ghostServer.start(ghostApp)
|
||||
.then(function afterStart() {
|
||||
logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's');
|
||||
});
|
||||
}).catch(function (err) {
|
||||
logging.error(err);
|
||||
setTimeout(() => {
|
||||
process.exit(-1);
|
||||
}, 100);
|
||||
});
|
|
@ -14,13 +14,10 @@ const knexMigrator = new KnexMigrator();
|
|||
// Ghost Internals
|
||||
const config = require('../../core/shared/config');
|
||||
const boot = require('../../core/boot');
|
||||
const express = require('../../core/shared/express');
|
||||
const ghost = require('../../core/server');
|
||||
const GhostServer = require('../../core/server/ghost-server');
|
||||
const {events} = require('../../core/server/lib/common');
|
||||
const db = require('../../core/server/data/db');
|
||||
const models = require('../../core/server/models');
|
||||
const urlUtils = require('../../core/shared/url-utils');
|
||||
const urlService = require('../../core/frontend/services/url');
|
||||
const settingsService = require('../../core/server/services/settings');
|
||||
const frontendSettingsService = require('../../core/frontend/services/settings');
|
||||
|
@ -216,21 +213,6 @@ const restartModeGhostStart = async () => {
|
|||
events.emit('server.start');
|
||||
};
|
||||
|
||||
// Old Boot Method
|
||||
// const bootGhost = async (options) => {
|
||||
// // Require Ghost
|
||||
// ghostServer = await ghost();
|
||||
|
||||
// // Mount Ghost & Start Server
|
||||
// if (options.subdir) {
|
||||
// let parentApp = express('test parent');
|
||||
// parentApp.use(urlUtils.getSubdir(), ghostServer.rootApp);
|
||||
// await ghostServer.start(parentApp);
|
||||
// } else {
|
||||
// await ghostServer.start();
|
||||
// }
|
||||
// };
|
||||
|
||||
const bootGhost = async () => {
|
||||
ghostServer = await boot();
|
||||
};
|
||||
|
|
|
@ -557,13 +557,6 @@
|
|||
jsonwebtoken "^8.5.1"
|
||||
lodash "^4.17.15"
|
||||
|
||||
"@tryghost/maintenance@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/maintenance/-/maintenance-0.1.0.tgz#cb2c4dff2c1292ca7a07b88f3a658832e33b3259"
|
||||
integrity sha512-f91Wngx4UbzGuSlCN6TI9EAvS1nofIYY653+3OO3fx/2A9ehbzMRWraUH3GY05xKRc8CnW+msGkRrPgiMIa/Kw==
|
||||
dependencies:
|
||||
ghost-ignition "^4.4.3"
|
||||
|
||||
"@tryghost/members-api@1.0.0-rc.3":
|
||||
version "1.0.0-rc.3"
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-1.0.0-rc.3.tgz#24dd56700f3da322a6a299a97b8632a1cae7db65"
|
||||
|
@ -4141,7 +4134,7 @@ ghost-ignition@4.2.4:
|
|||
prettyjson "1.2.1"
|
||||
uuid "8.3.1"
|
||||
|
||||
ghost-ignition@4.4.3, ghost-ignition@^4.4.3:
|
||||
ghost-ignition@4.4.3:
|
||||
version "4.4.3"
|
||||
resolved "https://registry.yarnpkg.com/ghost-ignition/-/ghost-ignition-4.4.3.tgz#c837ab11e1f3a1cfd22cc24df6b506a9afc1bc25"
|
||||
integrity sha512-eViE/ae+AGV/YmVbTq2W5TBWVu724EUJ0pjtSwa4q6o1+fXxMIqoELJaxMX+Gc9PBK0nI3J+E0JI8GdrEiqndg==
|
||||
|
|
Loading…
Reference in a new issue