Adding concurrency, and changing how context is set.

This commit is contained in:
mike12345567 2024-06-10 22:58:28 +01:00
parent a40baf5111
commit 8c1735a1bd
3 changed files with 40 additions and 45 deletions

View File

@ -13,8 +13,8 @@ export async function processMigrations(
) { ) {
console.log(`Processing app migration for "${appId}"`) console.log(`Processing app migration for "${appId}"`)
try { try {
// have to wrap in context, this gets the tenant from the app ID // first step - setup full context - tenancy, app and guards
await context.doInAppContext(appId, async () => { await context.doInAppMigrationContext(appId, async () => {
console.log(`Acquiring app migration lock for "${appId}"`) console.log(`Acquiring app migration lock for "${appId}"`)
await locks.doWithLock( await locks.doWithLock(
{ {
@ -23,48 +23,45 @@ export async function processMigrations(
resource: appId, resource: appId,
}, },
async () => { async () => {
await context.doInAppMigrationContext(appId, async () => { console.log(`Lock acquired starting app migration for "${appId}"`)
console.log(`Lock acquired starting app migration for "${appId}"`) let currentVersion = await getAppMigrationVersion(appId)
let currentVersion = await getAppMigrationVersion(appId)
const pendingMigrations = migrations const pendingMigrations = migrations
.filter(m => m.id > currentVersion) .filter(m => m.id > currentVersion)
.sort((a, b) => a.id.localeCompare(b.id)) .sort((a, b) => a.id.localeCompare(b.id))
const migrationIds = migrations.map(m => m.id).sort() const migrationIds = migrations.map(m => m.id).sort()
console.log( console.log(
`App migrations to run for "${appId}" - ${migrationIds.join(",")}` `App migrations to run for "${appId}" - ${migrationIds.join(",")}`
) )
let index = 0 let index = 0
for (const { id, func } of pendingMigrations) { for (const { id, func } of pendingMigrations) {
const expectedMigration = const expectedMigration =
migrationIds[migrationIds.indexOf(currentVersion) + 1] migrationIds[migrationIds.indexOf(currentVersion) + 1]
if (expectedMigration !== id) { if (expectedMigration !== id) {
throw new Error( throw new Error(
`Migration ${id} could not run, update for "${id}" is running but ${expectedMigration} is expected` `Migration ${id} could not run, update for "${id}" is running but ${expectedMigration} is expected`
) )
}
const counter = `(${++index}/${pendingMigrations.length})`
console.info(`Running migration ${id}... ${counter}`, {
migrationId: id,
appId,
})
await func()
await updateAppMigrationMetadata({
appId,
version: id,
})
currentVersion = id
} }
})
const counter = `(${++index}/${pendingMigrations.length})`
console.info(`Running migration ${id}... ${counter}`, {
migrationId: id,
appId,
})
await func()
await updateAppMigrationMetadata({
appId,
version: id,
})
currentVersion = id
}
} }
) )
console.log(`App migration for "${appId}" processed`)
}) })
console.log(`App migration for "${appId}" processed`)
} catch (err) { } catch (err) {
logging.logAlert("Failed to run app migration", err) logging.logAlert("Failed to run app migration", err)
throw err throw err

View File

@ -2,9 +2,10 @@ import { queue, logging } from "@budibase/backend-core"
import { Job } from "bull" import { Job } from "bull"
import { MIGRATIONS } from "./migrations" import { MIGRATIONS } from "./migrations"
import { processMigrations } from "./migrationsProcessor" import { processMigrations } from "./migrationsProcessor"
import { apiEnabled } from "../features"
const MAX_ATTEMPTS = 1 const MAX_ATTEMPTS = 3
// max number of migrations to run at same time, per node
const MIGRATION_CONCURRENCY = 5
export type AppMigrationJob = { export type AppMigrationJob = {
appId: string appId: string
@ -13,10 +14,6 @@ export type AppMigrationJob = {
let appMigrationQueue: queue.Queue<AppMigrationJob> | undefined let appMigrationQueue: queue.Queue<AppMigrationJob> | undefined
export function init() { export function init() {
// only run app migrations in main API services
if (!apiEnabled()) {
return
}
appMigrationQueue = queue.createQueue<AppMigrationJob>( appMigrationQueue = queue.createQueue<AppMigrationJob>(
queue.JobQueue.APP_MIGRATION, queue.JobQueue.APP_MIGRATION,
{ {
@ -34,10 +31,10 @@ export function init() {
} }
) )
return appMigrationQueue.process(processMessage) return appMigrationQueue.process(MIGRATION_CONCURRENCY, processMessage)
} }
async function processMessage(job: Job) { async function processMessage(job: Job<AppMigrationJob>) {
const { appId } = job.data const { appId } = job.data
await processMigrations(appId, MIGRATIONS) await processMigrations(appId, MIGRATIONS)

View File

@ -115,8 +115,9 @@ export async function startup(
// configure events to use the pro audit log write // configure events to use the pro audit log write
// can't integrate directly into backend-core due to cyclic issues // can't integrate directly into backend-core due to cyclic issues
queuePromises.push(events.processors.init(pro.sdk.auditLogs.write)) queuePromises.push(events.processors.init(pro.sdk.auditLogs.write))
queuePromises.push(appMigrations.init()) // app migrations and automations on other service
if (automationsEnabled()) { if (automationsEnabled()) {
queuePromises.push(appMigrations.init())
queuePromises.push(automations.init()) queuePromises.push(automations.init())
} }
queuePromises.push(initPro()) queuePromises.push(initPro())