Skip to content

Commit 86fc445

Browse files
kirrg001Mike
authored and
Mike
committed
🎨 run database population in transaction (TryGhost#7448)
* 🎨 run database population in transaction refs TryGhost#6574, refs TryGhost#7432 - create transaction for creating tables - if an error occurs or a container get's destroyed before population finishes, transaction is rolled back * 🎨 simplify transaction creation and test
1 parent cf7d2c1 commit 86fc445

File tree

4 files changed

+48
-24
lines changed

4 files changed

+48
-24
lines changed

‎core/server/data/migration/fixtures/populate.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ createOwner = function createOwner(logger, modelOptions) {
5656
password: coreUtils.uid(50)
5757
};
5858

59-
return models.Role.findOne({name: 'Owner'}).then(function (ownerRole) {
59+
return models.Role.findOne({name: 'Owner'}, modelOptions).then(function (ownerRole) {
6060
if (ownerRole) {
6161
user.roles = [ownerRole.id];
6262

‎core/server/data/migration/populate.js

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// # Populate
22
// Create a brand new database for a new install of ghost
33
var Promise = require('bluebird'),
4+
_ = require('lodash'),
45
commands = require('../schema').commands,
56
fixtures = require('./fixtures'),
67
errors = require('../../errors'),
8+
db = require('../../data/db'),
79
schema = require('../schema').tables,
810
schemaTables = Object.keys(schema),
911
populate, logger;
@@ -30,20 +32,24 @@ populate = function populate(options) {
3032
context: {
3133
internal: true
3234
}
33-
},
34-
tableSequence = Promise.mapSeries(schemaTables, function createTable(table) {
35-
logger.info('Creating table: ' + table);
36-
return commands.createTable(table);
37-
});
35+
};
3836

3937
logger.info('Creating tables...');
4038

41-
if (tablesOnly) {
42-
return tableSequence;
43-
}
39+
return db.knex.transaction(function populateDatabaseInTransaction(transaction) {
40+
return Promise.mapSeries(schemaTables, function createTable(table) {
41+
logger.info('Creating table: ' + table);
42+
return commands.createTable(table, transaction);
43+
}).then(function populateFixtures() {
44+
if (tablesOnly) {
45+
return;
46+
}
4447

45-
return tableSequence.then(function () {
46-
return fixtures.populate(logger, modelOptions);
48+
return fixtures.populate(logger, _.merge({}, {transacting: transaction}, modelOptions));
49+
});
50+
}).catch(function populateDatabaseError(err) {
51+
logger.warn('rolling back...');
52+
return Promise.reject(new errors.InternalServerError('Unable to populate database: ' + err.message));
4753
});
4854
};
4955

‎core/test/unit/migration_spec.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,12 @@ describe('Migrations', function () {
173173
var createStub, fixturesStub;
174174

175175
beforeEach(function () {
176-
createStub = sandbox.stub(schema.commands, 'createTable').returns(new Promise.resolve());
177176
fixturesStub = sandbox.stub(fixtures, 'populate').returns(new Promise.resolve());
178177
});
179178

180179
it('should create all tables, and populate fixtures', function (done) {
180+
createStub = sandbox.stub(schema.commands, 'createTable').returns(new Promise.resolve());
181+
181182
populate().then(function (result) {
182183
should.not.exist(result);
183184

@@ -190,18 +191,29 @@ describe('Migrations', function () {
190191
}).catch(done);
191192
});
192193

193-
it('should should only create tables, with tablesOnly setting', function (done) {
194-
populate({tablesOnly: true}).then(function (result) {
195-
should.exist(result);
196-
result.should.be.an.Array().with.lengthOf(schemaTables.length);
194+
it('should rollback if error occurs', function (done) {
195+
var i = 0;
197196

198-
createStub.called.should.be.true();
199-
createStub.callCount.should.be.eql(schemaTables.length);
200-
createStub.firstCall.calledWith(schemaTables[0]).should.be.true();
201-
createStub.lastCall.calledWith(schemaTables[schemaTables.length - 1]).should.be.true();
202-
fixturesStub.called.should.be.false();
203-
done();
204-
}).catch(done);
197+
createStub = sandbox.stub(schema.commands, 'createTable', function () {
198+
i = i + 1;
199+
200+
if (i > 10) {
201+
return new Promise.reject(new Error('error on table creation :('));
202+
}
203+
204+
return new Promise.resolve();
205+
});
206+
207+
populate()
208+
.then(function () {
209+
done(new Error('should throw an error for database population'));
210+
})
211+
.catch(function (err) {
212+
should.exist(err);
213+
(err instanceof errors.InternalServerError).should.eql(true);
214+
createStub.callCount.should.eql(11);
215+
done();
216+
});
205217
});
206218
});
207219

‎core/test/utils/index.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,13 @@ getFixtureOps = function getFixtureOps(toDos) {
459459
// Database initialisation
460460
if (toDos.init || toDos.default) {
461461
fixtureOps.push(function initDB() {
462-
return migration.populate({tablesOnly: tablesOnly});
462+
return new Promise(function initDb(resolve, reject) {
463+
migration.populate({tablesOnly: tablesOnly})
464+
.then(function () {
465+
resolve();
466+
})
467+
.catch(reject);
468+
});
463469
});
464470

465471
delete toDos.default;

0 commit comments

Comments
 (0)