Added bootstrap socket extension

refs https://github.com/TryGhost/Ghost-CLI/issues/759

- Ghost will announce the server start or failure in each case
- therefor you have to configure a bootstrap socket host and port
This commit is contained in:
kirrg001 2018-07-27 15:19:39 +02:00 committed by Katharina Irrgang
parent a7faab3956
commit 0e521792aa
3 changed files with 104 additions and 73 deletions

View File

@ -95,12 +95,6 @@ GhostServer.prototype.start = function (externalApp) {
self.httpServer.on('listening', function () {
debug('...Started');
// CASE: there are components which listen on this event to initialise after the server has started (in background)
// we want to avoid that they bootstrap during maintenance
if (config.get('maintenance:enabled') === false) {
common.events.emit('server.start');
}
self.logStartMessages();
resolve(self);
});
@ -162,8 +156,6 @@ GhostServer.prototype.hammertime = function () {
GhostServer.prototype.connection = function (socket) {
var self = this;
this.socket = socket;
self.connectionId += 1;
socket._ghostId = self.connectionId;
@ -174,10 +166,6 @@ GhostServer.prototype.connection = function (socket) {
self.connections[socket._ghostId] = socket;
};
GhostServer.prototype.getSocket = function getSocket() {
return this.socket;
};
/**
* ### Close Connections
* Most browsers keep a persistent connection open to the server, which prevents the close callback of
@ -241,3 +229,86 @@ GhostServer.prototype.logShutdownMessages = function () {
};
module.exports = GhostServer;
module.exports.announceServerStart = function announceServerStart() {
common.events.emit('server.start');
// CASE: IPC communication to the CLI via child process.
if (process.send) {
process.send({
started: true
});
}
// CASE: Ghost extension - bootstrap sockets
if (config.get('bootstrap-socket')) {
const socketAddress = config.get('bootstrap-socket');
const net = require('net');
const client = new net.Socket();
return new Promise((resolve) => {
const waitTimeout = setTimeout(() => {
client.destroy();
resolve();
}, 1000 * 5);
client.connect(socketAddress.port, socketAddress.host, () => {
if (waitTimeout) {
clearTimeout(waitTimeout);
}
client.write(JSON.stringify({started: true}));
resolve();
});
client.on('close', () => {
if (waitTimeout) {
clearTimeout(waitTimeout);
}
});
});
}
return Promise.resolve();
};
module.exports.announceServerStopped = function announceServerStopped(error) {
// CASE: IPC communication to the CLI via child process.
if (process.send) {
process.send({
started: false,
error: error
});
}
// CASE: Ghost extension - bootstrap sockets
if (config.get('bootstrap-socket')) {
const socketAddress = config.get('bootstrap-socket');
const net = require('net');
const client = new net.Socket();
return new Promise((resolve) => {
const waitTimeout = setTimeout(() => {
client.destroy();
resolve();
}, 1000 * 5);
client.connect(socketAddress.port, socketAddress.host, () => {
if (waitTimeout) {
clearTimeout(waitTimeout);
}
client.write(JSON.stringify({started: false, error: error}));
resolve();
});
client.on('close', () => {
if (waitTimeout) {
clearTimeout(waitTimeout);
}
});
});
}
return Promise.resolve();
};

View File

@ -103,20 +103,6 @@ const minimalRequiredSetupToStartGhost = (dbState) => {
return initialiseServices()
.then(() => {
// CASE: IPC communication to the CLI via child process.
if (process.send) {
process.send({
started: true
});
}
// CASE: Socket communication to the CLI. CLI started Ghost via systemd.
if (ghostServer.getSocket()) {
ghostServer.getSocket().write(JSON.stringify({
started: true
}));
}
return ghostServer;
});
}
@ -126,48 +112,24 @@ const minimalRequiredSetupToStartGhost = (dbState) => {
common.logging.info('Blog is in maintenance mode.');
config.set('maintenance:enabled', true);
migrator.migrate()
.then(() => {
common.events.emit('db.ready');
return initialiseServices();
})
.then(() => {
common.events.emit('server.start');
config.set('maintenance:enabled', false);
common.logging.info('Blog is out of maintenance mode.');
if (process.send) {
process.send({
started: true
});
}
// CASE: Socket communication to the CLI. CLI started Ghost via systemd.
if (ghostServer.getSocket()) {
ghostServer.getSocket().write(JSON.stringify({
started: true
}));
}
return GhostServer.announceServerStart();
})
.catch((err) => {
if (process.send) {
process.send({
started: false,
error: err.message
});
}
// CASE: Socket communication to the CLI. CLI started Ghost via systemd.
if (ghostServer.getSocket()) {
ghostServer.getSocket().write(JSON.stringify({
started: false,
error: err.message
}));
}
return GhostServer.announceServerStopped(err)
.finally(() => {
common.logging.error(err);
process.exit(-1);
});
});
return ghostServer;
}

View File

@ -3,7 +3,7 @@
var startTime = Date.now(),
debug = require('ghost-ignition').debug('boot:index'),
ghost, express, common, urlService, parentApp;
ghost, express, common, urlService, parentApp, config, GhostServer;
debug('First requires...');
@ -12,7 +12,8 @@ ghost = require('./core');
debug('Required ghost');
express = require('express');
common = require('./core/server/lib/common');
GhostServer = require('./core/server/ghost-server');
config = require('./core/server/config');
urlService = require('./core/server/services/url');
parentApp = express();
@ -23,13 +24,12 @@ ghost().then(function (ghostServer) {
debug('Starting Ghost');
// Let Ghost handle starting our server instance.
return ghostServer.start(parentApp).then(function afterStart() {
return ghostServer.start(parentApp)
.then(function afterStart() {
common.logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's');
// if IPC messaging is enabled, ensure ghost sends message to parent
// process on successful start
if (process.send) {
process.send({started: true});
if (!config.get('maintenance:enabled')) {
return GhostServer.announceServerStart();
}
});
}).catch(function (err) {
@ -37,11 +37,9 @@ ghost().then(function (ghostServer) {
err = new common.errors.GhostError({message: err.message, err: err});
}
return GhostServer.announceServerStopped(err)
.finally(() => {
common.logging.error(err);
if (process.send) {
process.send({started: false, error: err.message});
}
process.exit(-1);
});
});