2022-06-01 18:52:41 +02:00
|
|
|
import { migrations, redis } from "@budibase/backend-core"
|
2022-06-13 11:51:29 +02:00
|
|
|
import { Migration, MigrationOptions, MigrationName } from "@budibase/types"
|
|
|
|
import env from "../environment"
|
2022-01-24 11:48:59 +01:00
|
|
|
|
|
|
|
// migration functions
|
|
|
|
import * as userEmailViewCasing from "./functions/userEmailViewCasing"
|
|
|
|
import * as quota1 from "./functions/quotas1"
|
2022-01-27 11:40:31 +01:00
|
|
|
import * as appUrls from "./functions/appUrls"
|
2022-03-16 09:18:09 +01:00
|
|
|
import * as developerQuota from "./functions/developerQuota"
|
|
|
|
import * as publishedAppsQuota from "./functions/publishedAppsQuota"
|
2022-05-05 09:32:14 +02:00
|
|
|
import * as backfill from "./functions/backfill"
|
2022-01-24 11:48:59 +01:00
|
|
|
|
|
|
|
/**
|
2022-06-13 11:51:29 +02:00
|
|
|
* Populate the migration function and additional configuration from
|
|
|
|
* the static migration definitions.
|
2022-01-24 11:48:59 +01:00
|
|
|
*/
|
2022-06-13 11:51:29 +02:00
|
|
|
export const buildMigrations = () => {
|
|
|
|
const definitions = migrations.DEFINITIONS
|
|
|
|
const serverMigrations: Migration[] = []
|
|
|
|
|
|
|
|
for (const definition of definitions) {
|
|
|
|
switch (definition.name) {
|
|
|
|
case MigrationName.USER_EMAIL_VIEW_CASING: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
fn: userEmailViewCasing.run,
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.QUOTAS_1: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
fn: quota1.run,
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.APP_URLS: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
appOpts: { all: true },
|
|
|
|
fn: appUrls.run,
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.DEVELOPER_QUOTA: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
fn: developerQuota.run,
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.PUBLISHED_APP_QUOTA: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
fn: publishedAppsQuota.run,
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.EVENT_APP_BACKFILL: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
appOpts: { all: true },
|
|
|
|
fn: backfill.app.run,
|
|
|
|
silent: !!env.SELF_HOSTED, // reduce noisy logging
|
|
|
|
preventRetry: !!env.SELF_HOSTED, // only ever run once
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.EVENT_GLOBAL_BACKFILL: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
fn: backfill.global.run,
|
|
|
|
silent: !!env.SELF_HOSTED, // reduce noisy logging
|
|
|
|
preventRetry: !!env.SELF_HOSTED, // only ever run once
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case MigrationName.EVENT_INSTALLATION_BACKFILL: {
|
|
|
|
serverMigrations.push({
|
|
|
|
...definition,
|
|
|
|
fn: backfill.installation.run,
|
|
|
|
silent: !!env.SELF_HOSTED, // reduce noisy logging
|
|
|
|
preventRetry: !!env.SELF_HOSTED, // only ever run once
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2022-01-24 11:48:59 +01:00
|
|
|
}
|
2022-06-13 11:51:29 +02:00
|
|
|
|
|
|
|
return serverMigrations
|
2022-01-24 11:48:59 +01:00
|
|
|
}
|
|
|
|
|
2022-06-13 11:51:29 +02:00
|
|
|
export const MIGRATIONS = buildMigrations()
|
2022-01-24 11:48:59 +01:00
|
|
|
|
|
|
|
export const migrate = async (options?: MigrationOptions) => {
|
2022-06-01 18:52:41 +02:00
|
|
|
if (env.SELF_HOSTED) {
|
|
|
|
// self host runs migrations on startup
|
|
|
|
// make sure only a single instance runs them
|
|
|
|
await migrateWithLock(options)
|
|
|
|
} else {
|
|
|
|
await migrations.runMigrations(MIGRATIONS, options)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const migrateWithLock = async (options?: MigrationOptions) => {
|
|
|
|
// get a new lock client
|
|
|
|
const redlock = await redis.clients.getMigrationsRedlock()
|
|
|
|
// lock for 15 minutes
|
|
|
|
const ttl = 1000 * 60 * 15
|
|
|
|
|
|
|
|
let migrationLock
|
|
|
|
|
|
|
|
// acquire lock
|
|
|
|
try {
|
|
|
|
migrationLock = await redlock.lock("migrations", ttl)
|
|
|
|
} catch (e: any) {
|
|
|
|
if (e.name === "LockError") {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
throw e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// run migrations
|
|
|
|
try {
|
|
|
|
await migrations.runMigrations(MIGRATIONS, options)
|
|
|
|
} finally {
|
|
|
|
// release lock
|
|
|
|
try {
|
|
|
|
await migrationLock.unlock()
|
|
|
|
} catch (e) {
|
|
|
|
console.error("unable to release migration lock")
|
|
|
|
}
|
|
|
|
}
|
2022-01-24 11:48:59 +01:00
|
|
|
}
|