Skip to content

Commit

Permalink
updated schema and migrations
Browse files Browse the repository at this point in the history
  • Loading branch information
timgit committed Mar 1, 2017
1 parent 6170599 commit 64e66ab
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 24 deletions.
19 changes: 6 additions & 13 deletions src/migrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,30 @@ function getMigrations(schema) {
version: '2',
previous: '0.1.0',
install: [
`CREATE TYPE ${schema}.job_state AS ENUM (
'created',
'retry',
'active',
'complete',
'expired',
'cancelled'
)`,
`CREATE TYPE ${schema}.job_state AS ENUM ('created','retry','active','complete','expired','cancelled')`,
`ALTER TABLE ${schema}.job ALTER COLUMN state SET DATA TYPE ${schema}.job_state USING state::${schema}.job_state`,
`ALTER TABLE ${schema}.job DROP CONSTRAINT job_singleton`,
`ALTER TABLE ${schema}.job ADD singletonKey text`,
`CREATE UNIQUE INDEX job_singletonKeyOn ON ${schema}.job (name, singletonOn, singletonKey) WHERE state < 'complete'`,
`CREATE UNIQUE INDEX job_singletonOn ON ${schema}.job (name, singletonOn) WHERE state < 'complete' AND singletonKey IS NULL`,
`CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'complete' AND singletonOn IS NULL`,
`CREATE UNIQUE INDEX job_singletonOn ON ${schema}.job (name, singletonOn) WHERE state < 'expired' AND singletonKey IS NULL`,
`CREATE UNIQUE INDEX job_singletonKeyOn ON ${schema}.job (name, singletonOn, singletonKey) WHERE state < 'expired'`,
// migrate data to use retry state
`UPDATE ${schema}.job SET state = 'retry' WHERE state = 'expired' AND retryCount < retryLimit`,
// expired jobs weren't being archived in prev schema -- no rollback for this :)
// expired jobs weren't being archived in prev schema
`UPDATE ${schema}.job SET completedOn = now() WHERE state = 'expired' and retryLimit = retryCount`,
// just using good ole fashioned completedOn
`ALTER TABLE ${schema}.job DROP COLUMN expiredOn`
],
uninstall: [
`ALTER TABLE ${schema}.job ADD expiredOn timestamp without time zone`,
`DROP INDEX ${schema}.job_singletonKey`,
`DROP INDEX ${schema}.job_singletonOn`,
`DROP INDEX ${schema}.job_singletonKeyOn`,
`DROP INDEX ${schema}.job_singletonKey`,
`ALTER TABLE ${schema}.job DROP COLUMN singletonKey`,
`ALTER TABLE ${schema}.job ALTER COLUMN state SET DATA TYPE text`,
`DROP TYPE ${schema}.job_state`,
// restoring prev unique constraint
`ALTER TABLE ${schema}.job ADD CONSTRAINT job_singleton UNIQUE(name, singletonOn)`,
`ALTER TABLE ${schema}.job ADD expiredOn timestamp without time zone`,
// roll retry state back to expired
`UPDATE ${schema}.job SET state = 'expired' where state = 'retry'`
]
Expand Down
18 changes: 11 additions & 7 deletions src/plans.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ function createVersionTable(schema) {
}

function createJobStateEnum(schema) {
// ENUM definition order is important
// base type is numeric and first values are less than last values
return `
CREATE TYPE ${schema}.job_state AS ENUM (
'created',
Expand Down Expand Up @@ -67,22 +69,24 @@ function createJobTable(schema) {
)`;
}


function createIndexSingletonOn(schema){
function createIndexSingletonKey(schema){
// anything with singletonKey means "only 1 job can be queued or active at a time"
return `
CREATE UNIQUE INDEX job_singletonOn ON ${schema}.job (name, singletonOn) WHERE state < 'expired'
CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'complete' AND singletonOn IS NULL
`;
}

function createIndexSingletonKeyOn(schema){
function createIndexSingletonOn(schema){
// anything with singletonOn means "only 1 job within this time period, queued, active or completed"
return `
CREATE UNIQUE INDEX job_singletonKeyOn ON ${schema}.job (name, singletonOn, singletonKey) WHERE state < 'expired'
CREATE UNIQUE INDEX job_singletonOn ON ${schema}.job (name, singletonOn) WHERE state < 'expired' AND singletonKey IS NULL
`;
}

function createIndexSingletonKey(schema){
function createIndexSingletonKeyOn(schema){
// anything with both singletonOn and singletonKey means "only 1 job within this time period with this key, queued, active or completed"
return `
CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'complete'
CREATE UNIQUE INDEX job_singletonKeyOn ON ${schema}.job (name, singletonOn, singletonKey) WHERE state < 'expired'
`;
}

Expand Down
45 changes: 41 additions & 4 deletions test/migrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,65 @@ describe('migration', function() {
});

it('should migrate to previous version and back again', function (finished) {
this.timeout(3000);

contractor.create()
.then(() => db.migrate(currentSchemaVersion, 'remove'))
.then(version => {
assert.notEqual(version, currentSchemaVersion);
return db.migrate(version);
})
.then(version => {
assert.equal(version, currentSchemaVersion);
finished();
});
});

it('should migrate to latest during start if on previous schema version', function(finished){

contractor.create()
.then(() => db.migrate(currentSchemaVersion, 'remove'))
.then(() => new PgBoss(helper.config).start())
.then(() => contractor.version())
.then(version => {
assert(version);
assert.equal(version, currentSchemaVersion);
finished();
});
});

it('should migrate through 2 versions back and forth', function (finished) {

let prevVersion;

contractor.create()
.then(() => db.migrate(currentSchemaVersion, 'remove'))
.then(version => {
prevVersion = version;
assert.notEqual(version, currentSchemaVersion);

return db.migrate(version, 'remove');
})
.then(version => {
assert.notEqual(version, prevVersion);

return db.migrate(version);
})
.then(version => {
assert.equal(version, prevVersion);

return db.migrate(version);
})
.then(() => contractor.version())
.then(version => {
assert.equal(version, currentSchemaVersion);
finished();
});
});

it('should migrate to latest during start if on previous schema version', function(finished){

it('should migrate to latest during start if on previous 2 schema versions', function(finished){

contractor.create()
.then(() => db.migrate(currentSchemaVersion, 'remove'))
.then(version => db.migrate(version, 'remove'))
.then(() => new PgBoss(helper.config).start())
.then(() => contractor.version())
.then(version => {
Expand Down

0 comments on commit 64e66ab

Please sign in to comment.