2022-06-01 18:52:41 +02:00
|
|
|
import { migrations, redis } from "@budibase/backend-core"
|
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-05-25 01:15:52 +02:00
|
|
|
import env from "../environment"
|
2022-01-24 11:48:59 +01:00
|
|
|
|
|
|
|
export interface Migration {
|
|
|
|
type: string
|
|
|
|
name: string
|
2022-01-27 11:40:31 +01:00
|
|
|
opts?: object
|
2022-01-24 11:48:59 +01:00
|
|
|
fn: Function
|
2022-05-25 01:15:52 +02:00
|
|
|
silent?: boolean
|
2022-06-01 18:52:41 +02:00
|
|
|
preventRetry?: boolean
|
2022-01-24 11:48:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* e.g.
|
|
|
|
* {
|
|
|
|
* tenantIds: ['bb'],
|
|
|
|
* force: {
|
|
|
|
* global: ['quota_1']
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
export interface MigrationOptions {
|
|
|
|
tenantIds?: string[]
|
2022-03-08 15:21:41 +01:00
|
|
|
force?: {
|
2022-01-24 11:48:59 +01:00
|
|
|
[type: string]: string[]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-27 11:40:31 +01:00
|
|
|
export const MIGRATIONS: Migration[] = [
|
2022-01-24 11:48:59 +01:00
|
|
|
{
|
2022-05-04 12:22:50 +02:00
|
|
|
type: migrations.MIGRATION_TYPES.GLOBAL,
|
2022-01-24 11:48:59 +01:00
|
|
|
name: "user_email_view_casing",
|
|
|
|
fn: userEmailViewCasing.run,
|
|
|
|
},
|
|
|
|
{
|
2022-05-04 12:22:50 +02:00
|
|
|
type: migrations.MIGRATION_TYPES.GLOBAL,
|
2022-01-24 11:48:59 +01:00
|
|
|
name: "quotas_1",
|
|
|
|
fn: quota1.run,
|
|
|
|
},
|
2022-01-27 11:40:31 +01:00
|
|
|
{
|
2022-05-04 12:22:50 +02:00
|
|
|
type: migrations.MIGRATION_TYPES.APP,
|
2022-01-27 11:40:31 +01:00
|
|
|
name: "app_urls",
|
|
|
|
opts: { all: true },
|
|
|
|
fn: appUrls.run,
|
|
|
|
},
|
2022-03-04 14:42:50 +01:00
|
|
|
{
|
2022-05-04 12:22:50 +02:00
|
|
|
type: migrations.MIGRATION_TYPES.GLOBAL,
|
2022-03-16 09:18:09 +01:00
|
|
|
name: "developer_quota",
|
|
|
|
fn: developerQuota.run,
|
|
|
|
},
|
|
|
|
{
|
2022-05-04 12:22:50 +02:00
|
|
|
type: migrations.MIGRATION_TYPES.GLOBAL,
|
2022-03-16 09:18:09 +01:00
|
|
|
name: "published_apps_quota",
|
|
|
|
fn: publishedAppsQuota.run,
|
2022-03-04 14:42:50 +01:00
|
|
|
},
|
2022-05-04 12:22:50 +02:00
|
|
|
{
|
|
|
|
type: migrations.MIGRATION_TYPES.APP,
|
|
|
|
name: "event_app_backfill",
|
2022-05-05 09:32:14 +02:00
|
|
|
opts: { all: true },
|
|
|
|
fn: backfill.app.run,
|
2022-05-25 01:15:52 +02:00
|
|
|
silent: !!env.SELF_HOSTED, // reduce noisy logging
|
2022-06-01 18:52:41 +02:00
|
|
|
preventRetry: !!env.SELF_HOSTED, // only ever run once
|
2022-05-25 01:15:52 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
type: migrations.MIGRATION_TYPES.GLOBAL,
|
|
|
|
name: "event_global_backfill",
|
|
|
|
fn: backfill.global.run,
|
|
|
|
silent: !!env.SELF_HOSTED, // reduce noisy logging
|
2022-06-01 18:52:41 +02:00
|
|
|
preventRetry: !!env.SELF_HOSTED, // only ever run once
|
2022-05-04 12:22:50 +02:00
|
|
|
},
|
2022-05-27 00:57:14 +02:00
|
|
|
{
|
|
|
|
type: migrations.MIGRATION_TYPES.INSTALLATION,
|
|
|
|
name: "event_installation_backfill",
|
|
|
|
fn: backfill.installation.run,
|
|
|
|
silent: !!env.SELF_HOSTED, // reduce noisy logging
|
2022-06-01 18:52:41 +02:00
|
|
|
preventRetry: !!env.SELF_HOSTED, // only ever run once
|
2022-05-27 00:57:14 +02:00
|
|
|
},
|
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
|
|
|
}
|