diff --git a/core/boot.js b/core/boot.js index 0109f83c53..7abf5667e3 100644 --- a/core/boot.js +++ b/core/boot.js @@ -187,6 +187,19 @@ function mountGhost(rootApp, ghostApp) { debug('End: mountGhost'); } +// @TODO: make this notification different +function notifyReadiness(error) { + const notify = require('./server/notify'); + + if (error) { + debug('Notifying readiness (error)'); + notify.notifyServerStarted(error); + } else { + debug('Notifying readiness (success)'); + notify.notifyServerStarted(); + } +} + /** * ---------------------------------- * Boot Ghost - The magic starts here @@ -255,9 +268,8 @@ async function bootGhost() { // We are technically done here bootLogger.log('booted'); - // @TODO: make this notification different - // debug('boot notifying readiness'); - // GhostServer.notifyServerStarted(); + + notifyReadiness(); // Init our background jobs, we don't wait for this to finish initRecurringJobs({config}); @@ -267,8 +279,7 @@ async function bootGhost() { return ghostServer; } catch (error) { const errors = require('@tryghost/errors'); - // @TODO: fix these extra requires - const GhostServer = require('./server/ghost-server'); + // @TODO: fix this extra require const logging = require('./shared/logging'); let serverStartError = error; @@ -278,7 +289,7 @@ async function bootGhost() { } logging.error(serverStartError); - GhostServer.notifyServerStarted(serverStartError); + notifyReadiness(serverStartError); // If ghost was started and something else went wrong, we shut it down if (ghostServer) { diff --git a/core/server/ghost-server.js b/core/server/ghost-server.js index b85f2745b9..6a451a99ff 100644 --- a/core/server/ghost-server.js +++ b/core/server/ghost-server.js @@ -11,8 +11,8 @@ const urlUtils = require('./../shared/url-utils'); const errors = require('@tryghost/errors'); const {i18n} = require('./lib/common'); const logging = require('../shared/logging'); +const notify = require('./notify'); const moment = require('moment'); -const bootstrapSocket = require('@tryghost/bootstrap-socket'); const stoppable = require('stoppable'); /** @@ -109,7 +109,7 @@ class GhostServer { } debug('server notifying started'); - return GhostServer.notifyServerStarted() + return notify.notifyServerStarted() .finally(() => { resolve(self); }); @@ -288,55 +288,3 @@ class GhostServer { } module.exports = GhostServer; - -/** - * We call notify server started when the server is ready to serve traffic - * When the server is started, but not ready, it is only able to serve 503s - * - * If the server isn't able to reach started, notifyServerStarted is called with an error - * A status message, any error, and debug info are all passed to managing processes via IPC and the bootstrap socket - */ -let notifyServerStartedCalled = false; - -const debugInfo = { - versions: process.versions, - platform: process.platform, - arch: process.arch, - release: process.release -}; - -module.exports.notifyServerStarted = function (error = null) { - // If we already sent a ready notification, we should not do it again - if (notifyServerStartedCalled) { - return Promise.resolve(); - } - - // Mark this function as called - notifyServerStartedCalled = true; - - // Build our message - // - if there's no error then the server is ready - let message = { - started: true, - debug: debugInfo - }; - - // - if there's an error then the server is not ready, include the errors - if (error) { - message.started = false; - message.error = error; - } - - // CASE: IPC communication to the CLI for local process manager - if (process.send) { - process.send(message); - } - - // CASE: use bootstrap socket to communicate with CLI for systemd - let socketAddress = config.get('bootstrap-socket'); - if (socketAddress) { - return bootstrapSocket.connectAndSend(socketAddress, logging, message); - } - - return Promise.resolve(); -}; diff --git a/core/server/notify.js b/core/server/notify.js new file mode 100644 index 0000000000..d488e5cd87 --- /dev/null +++ b/core/server/notify.js @@ -0,0 +1,57 @@ +/** + * We call notify server started when the server is ready to serve traffic + * When the server is started, but not ready, it is only able to serve 503s + * + * If the server isn't able to reach started, notifyServerStarted is called with an error + * A status message, any error, and debug info are all passed to managing processes via IPC and the bootstrap socket + */ + +// Required Ghost internals +const config = require('../shared/config'); +const logging = require('../shared/logging'); + +let notifyServerStartedCalled = false; + +const debugInfo = { + versions: process.versions, + platform: process.platform, + arch: process.arch, + release: process.release +}; + +module.exports.notifyServerStarted = function (error = null) { + // If we already sent a ready notification, we should not do it again + if (notifyServerStartedCalled) { + return Promise.resolve(); + } + + // Mark this function as called + notifyServerStartedCalled = true; + + // Build our message + // - if there's no error then the server is ready + let message = { + started: true, + debug: debugInfo + }; + + // - if there's an error then the server is not ready, include the errors + if (error) { + message.started = false; + message.error = error; + } + + // CASE: IPC communication to the CLI for local process manager + if (process.send) { + process.send(message); + } + + // CASE: use bootstrap socket to communicate with CLI for systemd + let socketAddress = config.get('bootstrap-socket'); + if (socketAddress) { + const bootstrapSocket = require('@tryghost/bootstrap-socket'); + return bootstrapSocket.connectAndSend(socketAddress, logging, message); + } + + return Promise.resolve(); +}; diff --git a/test/unit/server/ghost-server_spec.js b/test/unit/server/notify_spec.js similarity index 84% rename from test/unit/server/ghost-server_spec.js rename to test/unit/server/notify_spec.js index b3636b03af..515f6593d7 100644 --- a/test/unit/server/ghost-server_spec.js +++ b/test/unit/server/notify_spec.js @@ -6,16 +6,16 @@ const {events} = require('../../../core/server/lib/common'); const bootstrapSocket = require('@tryghost/bootstrap-socket'); -describe('GhostServer', function () { +describe('Notify', function () { describe('notifyServerStarted', function () { - let GhostServer; + let notify; let socketStub; let eventSpy; beforeEach(function () { // Have to re-require each time to clear the internal flag - delete require.cache[require.resolve('../../../core/server/ghost-server')]; - GhostServer = require('../../../core/server/ghost-server'); + delete require.cache[require.resolve('../../../core/server/notify')]; + notify = require('../../../core/server/notify'); // process.send isn't set for tests, we can safely override; process.send = sinon.stub(); @@ -35,11 +35,11 @@ describe('GhostServer', function () { }); it('it resolves a promise', function () { - GhostServer.notifyServerStarted().should.be.fulfilled(); + notify.notifyServerStarted().should.be.fulfilled(); }); it('it communicates with IPC correctly on success', function () { - GhostServer.notifyServerStarted(); + notify.notifyServerStarted(); process.send.calledOnce.should.be.true(); @@ -50,7 +50,7 @@ describe('GhostServer', function () { }); it('communicates with IPC correctly on failure', function () { - GhostServer.notifyServerStarted(new Error('something went wrong')); + notify.notifyServerStarted(new Error('something went wrong')); process.send.calledOnce.should.be.true(); @@ -64,7 +64,7 @@ describe('GhostServer', function () { it('communicates via bootstrap socket correctly on success', function () { configUtils.set('bootstrap-socket', 'testing'); - GhostServer.notifyServerStarted(); + notify.notifyServerStarted(); socketStub.calledOnce.should.be.true(); socketStub.firstCall.args[0].should.eql('testing'); @@ -79,7 +79,7 @@ describe('GhostServer', function () { it('communicates via bootstrap socket correctly on failure', function () { configUtils.set('bootstrap-socket', 'testing'); - GhostServer.notifyServerStarted(new Error('something went wrong')); + notify.notifyServerStarted(new Error('something went wrong')); socketStub.calledOnce.should.be.true(); socketStub.firstCall.args[0].should.eql('testing'); @@ -95,9 +95,9 @@ describe('GhostServer', function () { it('can be called multiple times, but only communicates once', function () { configUtils.set('bootstrap-socket', 'testing'); - GhostServer.notifyServerStarted(); - GhostServer.notifyServerStarted(new Error('something went wrong')); - GhostServer.notifyServerStarted(); + notify.notifyServerStarted(); + notify.notifyServerStarted(new Error('something went wrong')); + notify.notifyServerStarted(); process.send.calledOnce.should.be.true(); socketStub.calledOnce.should.be.true(); diff --git a/test/utils/index.js b/test/utils/index.js index f789766941..ee1406b7d6 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -14,10 +14,10 @@ const knexMigrator = new KnexMigrator(); // Ghost Internals const config = require('../../core/shared/config'); const boot = require('../../core/boot'); -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 notify = require('../../core/server/notify'); const urlService = require('../../core/frontend/services/url'); const settingsService = require('../../core/server/services/settings'); const frontendSettingsService = require('../../core/frontend/services/settings'); @@ -252,7 +252,7 @@ const freshModeGhostStart = async (options) => { await bootGhost(options); // Ensure notify was called (this is idempotent) - GhostServer.notifyServerStarted(); + notify.notifyServerStarted(); // Wait for the URL service to be ready, which happens after boot, but don't re-trigger db.ready await urlServiceUtils.isFinished({disableDbReadyEvent: true});