budibase/packages/server/src/migrations/index.ts

130 lines
3.0 KiB
TypeScript
Raw Normal View History

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"
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"
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
silent?: boolean
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
{
type: migrations.MIGRATION_TYPES.GLOBAL,
2022-01-24 11:48:59 +01:00
name: "user_email_view_casing",
fn: userEmailViewCasing.run,
},
{
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
{
type: migrations.MIGRATION_TYPES.APP,
2022-01-27 11:40:31 +01:00
name: "app_urls",
opts: { all: true },
fn: appUrls.run,
},
{
type: migrations.MIGRATION_TYPES.GLOBAL,
name: "developer_quota",
fn: developerQuota.run,
},
{
type: migrations.MIGRATION_TYPES.GLOBAL,
name: "published_apps_quota",
fn: publishedAppsQuota.run,
},
{
type: migrations.MIGRATION_TYPES.APP,
name: "event_app_backfill",
2022-05-05 09:32:14 +02:00
opts: { all: true },
fn: backfill.app.run,
silent: !!env.SELF_HOSTED, // reduce noisy logging
preventRetry: !!env.SELF_HOSTED, // only ever run once
},
{
type: migrations.MIGRATION_TYPES.GLOBAL,
name: "event_global_backfill",
fn: backfill.global.run,
silent: !!env.SELF_HOSTED, // reduce noisy logging
preventRetry: !!env.SELF_HOSTED, // only ever run once
},
{
type: migrations.MIGRATION_TYPES.INSTALLATION,
name: "event_installation_backfill",
fn: backfill.installation.run,
silent: !!env.SELF_HOSTED, // reduce noisy logging
preventRetry: !!env.SELF_HOSTED, // only ever run once
},
2022-01-24 11:48:59 +01:00
]
export const migrate = async (options?: MigrationOptions) => {
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
}