0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

🐛 Fixed settings cache being out of sync after migrations (#11987)

refs https://github.com/TryGhost/Ghost/issues/10318

- re-initialize settings cache after migrations by shutting down to clean up event listeners then and calling `init` again
- important to ensure `db.ready` event is not emitted until settings have finished re-initializing to avoid problems with background processes using the db connection which is disconnected/re-connected or being kicked off with out-of-date settings
This commit is contained in:
Kevin Ansfield 2020-07-01 17:16:57 +01:00 committed by GitHub
parent cbdf33bfb7
commit fd4a011995
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 2 deletions

View file

@ -130,8 +130,10 @@ const minimalRequiredSetupToStartGhost = (dbState) => {
migrator.migrate()
.then(() => {
events.emit('db.ready');
return initialiseServices();
return settings.reinit().then(() => {
events.emit('db.ready');
return initialiseServices();
});
})
.then(() => {
config.set('maintenance:enabled', false);

View file

@ -14,5 +14,10 @@ module.exports = {
// This will bind to events for further updates
SettingsCache.init(settingsCollection);
});
},
reinit: function reinit() {
SettingsCache.shutdown();
return this.init();
}
};

View file

@ -1,6 +1,8 @@
const rewire = require('rewire');
const should = require('should');
const sinon = require('sinon');
const _ = require('lodash');
const {events} = require('../../../../core/server/lib/common');
const publicSettings = require('../../../../core/server/services/settings/public');
let cache = rewire('../../../../core/server/services/settings/cache');
@ -11,6 +13,10 @@ describe('UNIT: settings cache', function () {
cache = rewire('../../../../core/server/services/settings/cache');
});
afterEach(function () {
sinon.restore();
});
it('does not auto convert string into number', function () {
cache.set('key1', {value: '1'});
(typeof cache.get('key1')).should.eql('string');
@ -53,4 +59,41 @@ describe('UNIT: settings cache', function () {
cache.getPublic().should.eql(values);
});
it('can shutdown and init without double handling of events', function () {
const setSpy = sinon.spy(cache, 'set');
const settingsCollection = {
models: [{
get: () => 'key1',
toJSON: () => ({value: 'init value'})
}]
};
cache.init(settingsCollection);
cache.get('key1').should.equal('init value');
// check handler only called once on settings.edit
setSpy.callCount.should.equal(1);
events.emit('settings.edited', {
get: () => 'key1',
toJSON: () => ({value: 'first edit'})
});
setSpy.callCount.should.equal(2);
cache.get('key1').should.equal('first edit');
// shutdown + init
cache.shutdown();
cache.init(settingsCollection);
setSpy.callCount.should.equal(3);
cache.get('key1').should.equal('init value');
// edit again, check event only fired once
events.emit('settings.edited', {
get: () => 'key1',
toJSON: () => ({value: 'second edit'})
});
setSpy.callCount.should.equal(4);
cache.get('key1').should.equal('second edit');
});
});